diff -Naur lirc-0.7.0pre7/ChangeLog lirc-0.7.0pre7-streamzap-0.07/ChangeLog --- lirc-0.7.0pre7/ChangeLog 2004-07-25 12:56:47.000000000 -0400 +++ lirc-0.7.0pre7-streamzap-0.07/ChangeLog 2004-08-06 13:40:27.000000000 -0400 @@ -1,3 +1,10 @@ +2004-07-25 psypete + * drivers/Makefile.am, configure.in, setup.data: + fixed hunk failures from streamzap-0.6.diff. + * autogen.sh: + added from lirc cvs HEAD. why don't developers ever include this with + their source??? :P + 2004-07-25 lirc * doc/html-source/index.html, ANNOUNCE, configure.in, NEWS, setup.sh: diff -Naur lirc-0.7.0pre7/README.STREAMZAP lirc-0.7.0pre7-streamzap-0.07/README.STREAMZAP --- lirc-0.7.0pre7/README.STREAMZAP 1969-12-31 19:00:00.000000000 -0500 +++ lirc-0.7.0pre7-streamzap-0.07/README.STREAMZAP 2004-08-06 13:40:27.000000000 -0400 @@ -0,0 +1,8 @@ +Run autogen.sh to finish generating the makefiles, etc for the Streamzap. +Then run setup.sh and pick the Streamzap driver from the USB Devices section +of the driver-picker. +You also might want to put your kernel's sources in /usr/src/linux to make +configuration a tad easier :) +Then edit configure.sh if you want, and run it to configure lirc. +Then run make && make install. +Don't forget to copy/edit/use the streamzap config file! diff -Naur lirc-0.7.0pre7/autogen.sh lirc-0.7.0pre7-streamzap-0.07/autogen.sh --- lirc-0.7.0pre7/autogen.sh 1969-12-31 19:00:00.000000000 -0500 +++ lirc-0.7.0pre7-streamzap-0.07/autogen.sh 2004-08-06 13:40:27.000000000 -0400 @@ -0,0 +1,151 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. +# stolen from GtkEditor who stole it from GNOME. + +srcdir=`pwd` +DIE=0 + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`autoconf' installed to compile lirc." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && { + { (libtool --version) < /dev/null > /dev/null 2>&1 && LIBTOOLIZE=libtoolize; +} || + { (glibtool --version) < /dev/null > /dev/null 2>&1 && LIBTOOLIZE=glibtoolize +; } || + { + echo + echo "**Error**: You must have \`libtool' installed to compile lirc." + echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + } +} + +grep "^AM_GNU_GETTEXT" $srcdir/configure.in >/dev/null && { + grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \ + (gettext --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`gettext' installed to compile lirc." + echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + } +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`automake' installed to compile lirc." + echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.4.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + NO_AUTOMAKE=yes +} + + +# if no automake, don't bother testing for aclocal +test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: Missing \`aclocal'. The version of \`automake'" + echo "installed doesn't appear recent enough." + echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.4.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +#if test -z "$*"; then +# echo "**Warning**: I am going to run \`configure' with no arguments." +# echo "If you wish to pass any to it, please specify them on the" +# echo \`$0\'" command line." +# echo +#fi + +case $CC in +xlc ) + am_opt=--include-deps;; +esac + +# TW: all that happens for us at the moment is that aclocal, autoheader +# automake and autoconf asre called in the top level directory + +for coin in `find $srcdir -name configure.in -print` +do + dr=`dirname $coin` + if test -f $dr/NO-AUTO-GEN; then + echo skipping $dr -- flagged as no auto-gen + else + echo processing $dr + macrodirs=`sed -n -e 's,AM_ACLOCAL_INCLUDE(\(.*\)),\1,gp' < $coin` + ( cd $dr + aclocalinclude="$ACLOCAL_FLAGS" + for k in $macrodirs; do + if test -d $k; then + aclocalinclude="$aclocalinclude -I $k" + ##else + ## echo "**Warning**: No such directory \`$k'. Ignored." + fi + done + if grep "^AM_GNU_GETTEXT" configure.in >/dev/null; then + if grep "sed.*POTFILES" configure.in >/dev/null; then + : do nothing -- we still have an old unmodified configure.in + else + echo "Creating $dr/aclocal.m4 ..." + test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 + echo "Running gettextize... Ignore non-fatal messages." + echo "no" | gettextize --force --copy + echo "Making $dr/aclocal.m4 writable ..." + test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 + fi + fi + if grep "^AM_GNOME_GETTEXT" configure.in >/dev/null; then + echo "Creating $dr/aclocal.m4 ..." + test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 + echo "Running gettextize... Ignore non-fatal messages." + echo "no" | gettextize --force --copy + echo "Making $dr/aclocal.m4 writable ..." + test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 + fi + if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then + echo "Running libtoolize..." + $LIBTOOLIZE --force --copy + fi + echo "Running aclocal $aclocalinclude ..." + aclocal $aclocalinclude + if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then + echo "Running autoheader..." + autoheader + fi + echo "Running automake --gnu $am_opt ..." + automake --add-missing --gnu $am_opt + echo "Running autoconf ..." + autoconf + ) + fi +done + +echo "Creating setup-driver.sh ..." +./data2setup.sh > setup-driver.sh + +# TW: we don't want autogen running configure for us -- there's far too +# many options which need setting + +# conf_flags="--enable-maintainer-mode --enable-compile-warnings" #--enable-iso +-c +# +#if test x$NOCONFIGURE = x; then +# echo Running $srcdir/configure $conf_flags "$@" ... +# $srcdir/configure $conf_flags "$@" \ +# && echo Now type \`make\' to compile $PKG_NAME +#else +# echo Skipping configure process. +#fi + diff -Naur lirc-0.7.0pre7/configure.in lirc-0.7.0pre7-streamzap-0.07/configure.in --- lirc-0.7.0pre7/configure.in 2004-07-25 12:54:59.000000000 -0400 +++ lirc-0.7.0pre7-streamzap-0.07/configure.in 2004-08-06 13:40:27.000000000 -0400 @@ -145,8 +145,9 @@ possible_drivers="${possible_drivers} (lirc_dev lirc_serial) \ (lirc_dev lirc_sir) (lirc_dev lirc_parallel) (lirc_dev lirc_i2c) \ (lirc_dev lirc_gpio) (lirc_dev) (lirc_dev lirc_it87) \ - (lirc_dev lirc_bt829) (lirc_dev lirc_atiusb) \ - (lirc_dev lirc_mceusb) (lirc_dev lirc_sasem)" + (lirc_dev lirc_bt829) (lirc_dev lirc_atiusb) \ + (lirc_dev lirc_mceusb) (lirc_dev lirc_sasem) \ + (lirc_dev lirc_streamzap)" fi AC_CHECK_LIB(caraca_client, caraca_init, @@ -197,8 +198,8 @@ pctv, pixelview_bt878, pixelview_pak, pixelview_pro, provideo, realmagic, remotemaster, sa1100, sasem, serial, silitek, - sir, slinke, tekram, tekram_bt829, tira, - tvbox, udp, uirt2, uirt2_raw], + sir, slinke, streamzap, tekram, tekram_bt829, + tira, tvbox, udp, uirt2, uirt2_raw], driver=${withval}, driver="unset" ) @@ -294,6 +295,8 @@ ;; lirc_dev-lirc_sir) ;; + lirc_dev-lirc_streamzap) + ;; lirc_flyvideo) ;; livedrive_midi) @@ -758,6 +761,11 @@ HW_DEFAULT="hw_slinke" fi +if test "$driver" = "streamzap"; then + lirc_driver="lirc_dev lirc_streamzap" + lircd_conf="streamzap/lircd.conf.streamzap" +fi + if test "$driver" = "tekram"; then lirc_driver="lirc_dev lirc_sir" AC_DEFINE(LIRC_SIR_TEKRAM) @@ -1048,6 +1056,7 @@ drivers/lirc_dev/Makefile drivers/lirc_it87/Makefile drivers/lirc_bt829/Makefile + drivers/lirc_streamzap/Makefile drivers/lirc_atiusb/Makefile drivers/lirc_mceusb/Makefile drivers/lirc_sasem/Makefile diff -Naur lirc-0.7.0pre7/daemons/receive.c lirc-0.7.0pre7-streamzap-0.07/daemons/receive.c --- lirc-0.7.0pre7/daemons/receive.c 2004-04-27 14:51:17.000000000 -0400 +++ lirc-0.7.0pre7-streamzap-0.07/daemons/receive.c 2004-08-06 13:40:27.000000000 -0400 @@ -55,7 +55,7 @@ { lirc_t data; - data=hw.readdata(2*maxusec<50000 ? 50000:2*maxusec); + data=hw.readdata(2*maxusec<500000 ? 500000:2*maxusec); if(!data) { return 0; diff -Naur lirc-0.7.0pre7/drivers/Makefile.am lirc-0.7.0pre7-streamzap-0.07/drivers/Makefile.am --- lirc-0.7.0pre7/drivers/Makefile.am 2004-06-19 02:56:28.000000000 -0400 +++ lirc-0.7.0pre7-streamzap-0.07/drivers/Makefile.am 2004-08-06 13:40:27.000000000 -0400 @@ -8,7 +8,7 @@ EXTRA_DIST = lirc.h kcompat.h Makefile.kernel Makefile.common DIST_SUBDIRS = lirc_serial lirc_parallel lirc_i2c lirc_sir lirc_dev lirc_gpio \ - lirc_it87 lirc_bt829 lirc_atiusb lirc_mceusb lirc_sasem + lirc_it87 lirc_bt829 lirc_atiusb lirc_mceusb lirc_sasem lirc_streamzap SUBDIRS = @lirc_driver@ CLEANFILES = *~ diff -Naur lirc-0.7.0pre7/drivers/lirc_dev/lirc_dev.c lirc-0.7.0pre7-streamzap-0.07/drivers/lirc_dev/lirc_dev.c --- lirc-0.7.0pre7/drivers/lirc_dev/lirc_dev.c 2004-04-08 17:17:46.000000000 -0400 +++ lirc-0.7.0pre7-streamzap-0.07/drivers/lirc_dev/lirc_dev.c 2004-08-06 13:40:27.000000000 -0400 @@ -91,6 +91,7 @@ struct semaphore *t_notify2; int shutdown; long jiffies_to_wait; + int force_unregister; #ifdef LIRC_HAVE_DEVFS devfs_handle_t devfs_handle; @@ -99,7 +100,7 @@ DECLARE_MUTEX(plugin_lock); -static struct irctl irctls[MAX_IRCTL_DEVICES]; +static struct irctl *irctls[MAX_IRCTL_DEVICES]; static struct file_operations fops; @@ -116,6 +117,7 @@ ir->t_notify2 = NULL; ir->shutdown = 0; ir->jiffies_to_wait = 0; + ir->force_unregister = 0; ir->open = 0; } @@ -234,7 +236,7 @@ if (MAX_IRCTL_DEVICES <= p->minor) { printk("lirc_dev: lirc_register_plugin:" - "\" minor\" must be between 0 and %d (%d)!\n", + " \"minor\" must be between 0 and %d (%d)!\n", MAX_IRCTL_DEVICES-1, p->minor); return -EBADRQC; } @@ -276,14 +278,14 @@ } } - down_interruptible(&plugin_lock); + down(&plugin_lock); minor = p->minor; if (0 > minor) { /* find first free slot for plugin */ for (minor=0; minorsample_rate) { ir->jiffies_to_wait = HZ / p->sample_rate; @@ -316,6 +320,7 @@ ir->buf = p->rbuf; } else { ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); +#warning kmalloc may fail lirc_buffer_init(ir->buf, bytes_in_key, BUFLEN/bytes_in_key); } @@ -361,6 +366,9 @@ /* * */ +static void irctl_free(struct irctl *ir); +static int do_irctl_plugin_close(struct irctl *ir); + int lirc_unregister_plugin(int minor) { struct irctl *ir; @@ -369,16 +377,17 @@ if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { printk("lirc_dev: lirc_unregister_plugin:" - "\" minor\" must be between 0 and %d!\n", + " \"minor\" must be between 0 and %d!\n", MAX_IRCTL_DEVICES-1); return -EBADRQC; } - ir = &irctls[minor]; + down(&plugin_lock); - down_interruptible(&plugin_lock); + ir = irctls[minor]; + irctls[minor] = NULL; - if (ir->p.minor != minor) { + if (!ir) { printk("lirc_dev: lirc_unregister_plugin:" "minor (%d) device not registered!", minor); up(&plugin_lock); @@ -388,8 +397,15 @@ 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; + if(ir->p.fops && ir->p.fops->release){ + /* we can't reliably force unregister in this case */ + up(&plugin_lock); + return -EBUSY; + } else { + do_irctl_plugin_close(ir); + ir->force_unregister=1; + wake_up_all(&ir->buf->wait_poll); + } } /* end up polling thread */ @@ -420,17 +436,25 @@ #ifdef LIRC_HAVE_DEVFS devfs_unregister(ir->devfs_handle); #endif + + if(!ir->force_unregister) + irctl_free(ir); + + up(&plugin_lock); + return SUCCESS; +} + +static void irctl_free(struct irctl *ir) +{ if (ir->buf != ir->p.rbuf){ lirc_buffer_free(ir->buf); kfree(ir->buf); } ir->buf = NULL; - init_irctl(ir); - up(&plugin_lock); - MOD_DEC_USE_COUNT; + kfree(ir); - return SUCCESS; + MOD_DEC_USE_COUNT; } /* @@ -447,23 +471,25 @@ return -ENODEV; } - ir = &irctls[MINOR(inode->i_rdev)]; + if (down_interruptible(&plugin_lock)) return -ERESTARTSYS; - dprintk(LOGHEAD "open called\n", ir->p.name, ir->p.minor); + ir = irctls[MINOR(inode->i_rdev)]; - /* 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) { + if(!ir){ up(&plugin_lock); dprintk(LOGHEAD "open result = -ENODEV\n", - ir->p.name, ir->p.minor); + "NULL", MINOR(inode->i_rdev)); return -ENODEV; } + 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){ + up(&plugin_lock); + return ir->p.fops->open(inode, file); + } + if (ir->open) { up(&plugin_lock); dprintk(LOGHEAD "open result = -EBUSY\n", @@ -488,6 +514,7 @@ --ir->open; return retval; } + file->private_data = ir; dprintk(LOGHEAD "open result = %d\n", ir->p.name, ir->p.minor, SUCCESS); @@ -499,21 +526,31 @@ */ static int irctl_close(struct inode *inode, struct file *file) { - struct irctl *ir = &irctls[MINOR(inode->i_rdev)]; - + struct irctl *ir = file->private_data; + int retval; dprintk(LOGHEAD "close called\n", ir->p.name, ir->p.minor); + + if(ir->force_unregister && !ir->open) { + /* do_irctl_plugin_close got called already for + * simulating a close on the forced unregister */ + irctl_free(ir); + return SUCCESS; + } /* 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); + if (down_interruptible(&plugin_lock)) return -ERESTARTSYS; + retval = do_irctl_plugin_close(ir); + up(&plugin_lock); + return retval; +} +static int do_irctl_plugin_close(struct irctl *ir) +{ --ir->open; ir->p.set_use_dec(ir->p.data); - - up(&plugin_lock); - return SUCCESS; } @@ -522,7 +559,10 @@ */ static unsigned int irctl_poll(struct file *file, poll_table *wait) { - struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct irctl *ir = file->private_data; + + if(ir->force_unregister) + return -ENODEV; dprintk(LOGHEAD "poll called\n", ir->p.name, ir->p.minor); @@ -547,7 +587,10 @@ { unsigned long mode; int result; - struct irctl *ir = &irctls[MINOR(inode->i_rdev)]; + struct irctl *ir = file->private_data; + + if(ir->force_unregister) + return -ENODEV; dprintk(LOGHEAD "ioctl called (%u)\n", ir->p.name, ir->p.minor, cmd); @@ -618,13 +661,16 @@ size_t length, loff_t *ppos) { - struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct irctl *ir = file->private_data; 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(ir->force_unregister) + return -ENODEV; + /* 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); @@ -646,6 +692,8 @@ * mode and 'copy_to_user' is happy, wait for data. */ while (written < length && ret == 0) { + if (ir->force_unregister) + break; if (lirc_buffer_empty(ir->buf)) { /* According to the read(2) man page, 'written' can be * returned as less than 'length', instead of blocking @@ -688,10 +736,13 @@ 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)]; + struct irctl *ir = file->private_data; dprintk(LOGHEAD "read called\n", ir->p.name, ir->p.minor); + if(ir->force_unregister) + return -ENODEV; + /* 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); @@ -721,10 +772,6 @@ { int i; - for (i=0; i < MAX_IRCTL_DEVICES; ++i) { - init_irctl(&irctls[i]); - } - #ifndef LIRC_HAVE_DEVFS i = register_chrdev(IRCTL_DEV_MAJOR, #else diff -Naur lirc-0.7.0pre7/drivers/lirc_streamzap/Makefile.am lirc-0.7.0pre7-streamzap-0.07/drivers/lirc_streamzap/Makefile.am --- lirc-0.7.0pre7/drivers/lirc_streamzap/Makefile.am 1969-12-31 19:00:00.000000000 -0500 +++ lirc-0.7.0pre7-streamzap-0.07/drivers/lirc_streamzap/Makefile.am 2004-08-06 13:40:27.000000000 -0400 @@ -0,0 +1,48 @@ +## Process this file with automake to produce Makefile.in + +## this is so that Automake includes the C compiling definitions, and +## includes the source files in the distribution. +EXTRA_PROGRAMS = automake_dummy +automake_dummy_SOURCES = lirc_streamzap.c + +## there is no *just* object file support in automake. This is close enough +module_DATA = lirc_streamzap.o + +# where the kernel sources are located +KERNEL_LOCATION=@kerneldir@ + +# some magic for using linux kernel settings +# when compiling module(s) +CC = @kernelcc@ +MI_OBJS = $(module_DATA) +EXTRA_CFLAGS = $(DEFS) $(DEFAULT_INCLUDES) + +$(module_DATA): $(automake_dummy_SOURCES) $(top_srcdir)/config.h ../lirc.h + ifndef MAKING_MODULES + DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR obj-m=$(module_DATA) modules) + endif +# the spaces above are necessary because automake otherwise will complain +# and even worse, it will delete the line + +if SANDBOXED +else +install-exec-local: mkdev +uninstall-local: rmdev +endif + +mkdev: + test -c $(DESTDIR)$(devdir)/lirc || ($(mkinstalldirs) $(DESTDIR)$(devdir) && @mknod@ $(DESTDIR)$(devdir)/lirc c @lirc_major@ 0) + +rmdev: + -test -c $(DESTDIR)$(devdir)/lirc && $(RM) $(DESTDIR)$(devdir)/lirc + +if SANDBOXED +else +install-data-local: install-moduleDATA + -@depmod@ -a +endif + +CLEANFILES = $(module_DATA) .$(module_DATA).flags *~ + +include $(KERNEL_LOCATION)/Rules.make + diff -Naur lirc-0.7.0pre7/drivers/lirc_streamzap/lirc_streamzap.c lirc-0.7.0pre7-streamzap-0.07/drivers/lirc_streamzap/lirc_streamzap.c --- lirc-0.7.0pre7/drivers/lirc_streamzap/lirc_streamzap.c 1969-12-31 19:00:00.000000000 -0500 +++ lirc-0.7.0pre7-streamzap-0.07/drivers/lirc_streamzap/lirc_streamzap.c 2004-08-06 13:40:27.000000000 -0400 @@ -0,0 +1,449 @@ +/* lirc_streamzap - USB StreamZap remote driver + * Alpha status, currently Works For Me(tm). Feedback welcome. + * Version 0.06 + * + * Copyright (C) 2002-2003 Adrian Dewhurst + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#ifdef CONFIG_SMP +# define __SMP__ +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#error "*******************************************************" +#error "Sorry, this driver needs kernel version 2.4.0 or higher" +#error "*******************************************************" +#endif + +#include +#include +#include +#include +#include +#include + +#include "drivers/lirc.h" +#include "drivers/lirc_dev/lirc_dev.h" + +#ifdef CONFIG_USB_DEBUG +static int debug = 1; +#else +static int debug; +#endif +static int minor = -1; + +#undef dbg +#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) + +#define DRIVER_VERSION "v0.06" +#define DRIVER_AUTHOR "Adrian Dewhurst, sailor-lk@sailorfrag.net" +#define DRIVER_DESC "lirc USB StreamZap Remote driver" +#define LIRC_DRIVER_NAME "lirc_streamzap" +#define USB_STREAMZAP_VENDOR_ID 0x0e9c +#define USB_STREAMZAP_PRODUCT_ID 0x0000 + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); +MODULE_PARM(minor, "i"); +MODULE_PARM_DESC(minor, "Preferred minor to use for LIRC device"); + +EXPORT_NO_SYMBOLS; + +static struct usb_device_id streamzap_table [] = { + { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, streamzap_table); + +struct usb_streamzap { + struct usb_device *udev; /* usb device struct; NULL upon disconnect */ + struct lirc_plugin plugin; /* our lirc_dev device info */ + struct urb irq; /* our interrupt URB */ + + __u16 int_in_size; /* size of interrupt buffer */ + unsigned char *int_in_buffer; /* URB interrupt buffer */ + + unsigned char tmpbuf; /* for tracking long codes between interrupts */ + unsigned char ign; + struct lirc_buffer outbuf; /* kernel space -> user space buffer */ + spinlock_t interrupt_lock; + + unsigned int open_count; + + struct semaphore lock; /* locks this structure */ +}; + +/* USB functions */ +static void streamzap_irq(struct urb *urb); +static void * streamzap_probe(struct usb_device *dev, unsigned intf, const struct usb_device_id *id); +static void streamzap_disconnect(struct usb_device *dev, void *data); + +static struct usb_driver streamzap_driver = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20) + owner: THIS_MODULE, +#endif + name: "lirc_streamzap", + probe: streamzap_probe, + disconnect: streamzap_disconnect, + id_table: streamzap_table, +}; + +/* LIRC functions */ +static int streamzap_use_inc(void *data); +static void streamzap_use_dec(void *data); + +static struct lirc_plugin streamzap_lirc_template = { + minor: -1, /* Fill this in */ + sample_rate: 0, + code_length: 32, + features: LIRC_CAN_REC_MODE2, + data: NULL, /* Fill this in */ + rbuf: NULL, /* Fill this in */ + set_use_inc: streamzap_use_inc, + set_use_dec: streamzap_use_dec, +}; + +/* USB */ +static void * streamzap_probe(struct usb_device *dev, unsigned intf, const struct usb_device_id *id) { + struct usb_interface *iface; + struct usb_interface_descriptor *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct usb_streamzap *sz = NULL; + int pipe; + int result; + char buf[63], name[128]=""; + + /* Get the device */ + iface = &dev->actconfig->interface[intf]; + iface_desc = &iface->altsetting[iface->act_altsetting]; + + /* Find out if we want it */ + if ((dev->descriptor.idVendor != USB_STREAMZAP_VENDOR_ID) || + (dev->descriptor.idProduct != USB_STREAMZAP_PRODUCT_ID)) { + return NULL; + } + + /* Find the endpoint */ + if (iface_desc->bNumEndpoints != 1) return NULL; + endpoint = iface_desc->endpoint + 0; + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN) return NULL; + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return NULL; + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + + /* Allocate our device struct */ + if (!(sz = kmalloc(sizeof(*sz), GFP_KERNEL))) { + err("Out of memory allocating streamzap device"); + return NULL; + } + memset(sz, 0, sizeof(*sz)); + + /* Initialize locks and data */ + sz->udev = dev; + init_MUTEX(&sz->lock); + spin_lock_init(&sz->interrupt_lock); + + /* Allocate the URB buffer */ + sz->int_in_size = endpoint->wMaxPacketSize; + if (!(sz->int_in_buffer = kmalloc(sz->int_in_size, GFP_KERNEL))) { + err("Out of memory allocating streamzap interrupt buffer"); + goto error; + } + FILL_INT_URB(&sz->irq, dev, pipe, sz->int_in_buffer, sz->int_in_size, streamzap_irq, sz, endpoint->bInterval); + dbg("buffer_size %hu, buffer %p, interval %hu", sz->int_in_size, sz->int_in_buffer, endpoint->bInterval); + + /* Allocate the lirc buffer */ + lirc_buffer_init(&sz->outbuf, 4 /* 32 bits/chunk */, 128 /* the default size of 16 is a bit small */); + + /* Set up the lirc plugin struct */ + memcpy(&sz->plugin, &streamzap_lirc_template, sizeof(struct lirc_plugin)); + sz->plugin.data = sz; + sz->plugin.rbuf = &sz->outbuf; + sz->plugin.minor = minor; + + /* Set up the plugin interface */ + dbg("Attempting to register plugin on minor %d", sz->plugin.minor); + if ((result = lirc_register_plugin(&sz->plugin)) < 0) { +#if 0 + /* It might be just that the preferred minor is in use. Try again + * without trying for a specific minor. */ + if (result == -EBUSY) { + info("lirc_streamzap: usb%d:%d.%d: Preferred minor %d already in use. Trying another.", dev->bus->busnum, dev->devnum, intf, minor); + sz->plugin.minor = -1; + if ((result = lirc_register_plugin(&sz->plugin)) < 0) { + goto error2; + } + } else { + goto error2; + } +#else + goto error2; +#endif + } + sz->plugin.minor = result; + dbg("Registered on minor %d", sz->plugin.minor); + + /* Grab the USB name string */ + if (dev->descriptor.iManufacturer && usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) strcpy(name, buf); + if (dev->descriptor.iProduct && usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) sprintf(name, "%s %s", name, buf); + info("lirc%d: %s on usb%d:%d.%d", sz->plugin.minor, name, dev->bus->busnum, dev->devnum, intf); + + goto exit; + +error2: + err("usb%d:%d.%d: Unable to register plugin with lirc_dev.", dev->bus->busnum, dev->devnum, intf); + lirc_buffer_free(&sz->outbuf); + kfree(sz->int_in_buffer); +error: + kfree(sz); + sz=NULL; +exit: + return sz; +} + +static void streamzap_disconnect(struct usb_device *udev, void *data) +{ + struct usb_streamzap *sz=(struct usb_streamzap *)data; + int result, flags; + + dbg("Entering streamzap_disconnect"); + + /* Stop everything else */ + sz->udev = NULL; + + down(&sz->lock); + if (sz->open_count) { + spin_lock_irqsave(&sz->interrupt_lock, flags); + usb_unlink_urb(&sz->irq); + spin_unlock_irqrestore(&sz->interrupt_lock, flags); + } + + info("lirc%d: disconnected", sz->plugin.minor); + + if ((result = lirc_unregister_plugin(sz->plugin.minor))) { + err("lirc_unregister_plugin(%d) failed: %d", sz->plugin.minor, result); + } + lirc_buffer_free(&sz->outbuf); + kfree(sz->int_in_buffer); + kfree(sz); +} + +static inline void usb_streamzap_debug_data(const char *function, int size, const unsigned char *data) +{ + int i; + + if (!debug) return; + + printk(KERN_DEBUG __FILE__": %s: length %d, data ", function, size); + for (i = 0; i < size; ++i) { + printk("%.2x ", data[i]); + } + printk("\n"); +} + +static void streamzap_irq(struct urb *urb) +{ + struct usb_streamzap *sz=urb->context; + unsigned long flags; + unsigned int i=0; + uint32_t tmp; + + if (urb->status) return; + if (urb->actual_length == 0) return; + + if (!sz) { + dbg("streamzap_irq called with no context"); + usb_unlink_urb(urb); + return; + } + + usb_streamzap_debug_data(__FUNCTION__, urb->actual_length, urb->transfer_buffer); + + spin_lock_irqsave(&sz->interrupt_lock, flags); + /* I can't really explain how this works (StreamZap's request). It should + * work properly though. */ +#define check_buffer() if (lirc_buffer_full(&sz->outbuf)) { err("lirc%d: out of buffer space", sz->plugin.minor); goto out; } + if (sz->tmpbuf) { + if ((sz->tmpbuf & 0xf0) == 0xf0) { + check_buffer(); + tmp = (sz->int_in_buffer[0] * 256) | 0x01000000; + lirc_buffer_write_1(&sz->outbuf, (char *)&tmp); + + sz->ign = 1; + } else { + if (!sz->ign) { + tmp = (((sz->tmpbuf & 0xf0) >> 4) * 256); + tmp = (tmp ? tmp : 1) | 0x01000000; + lirc_buffer_write_1(&sz->outbuf, (char *)&tmp); + } + + check_buffer(); + tmp = sz->int_in_buffer[0] * 256; + tmp = tmp ? tmp : 1; + lirc_buffer_write_1(&sz->outbuf, (char *)&tmp); + + sz->ign = 0; + } + + sz->tmpbuf = 0; + i++; + } + + for (; i < urb->actual_length; i++) { + if ((sz->int_in_buffer[i] & 0xf0) == 0xf0 || (sz->int_in_buffer[i] & 0x0f) == 0x0f) { + if (i+1 >= urb->actual_length) { + sz->tmpbuf = sz->int_in_buffer[i]; + break; + } + + if ((sz->int_in_buffer[i] & 0xf0) == 0xf0) { + check_buffer(); + tmp = sz->int_in_buffer[i+1] * 256; + tmp = (tmp ? tmp : 1) | 0x01000000; + lirc_buffer_write_1(&sz->outbuf, (char *)&tmp); + + sz->ign = 1; + } else { + if (!sz->ign) { + check_buffer(); + tmp = ((sz->int_in_buffer[i] & 0xf0) >> 4) * 256; + tmp = (tmp ? tmp : 1) | 0x01000000; + lirc_buffer_write_1(&sz->outbuf, (char *)&tmp); + } + + check_buffer(); + tmp = sz->int_in_buffer[i+1] * 256; + tmp = (tmp ? tmp : 1); + lirc_buffer_write_1(&sz->outbuf, (char *)&tmp); + + sz->ign = 0; + } + i++; + } else { + check_buffer(); + tmp = ((sz->int_in_buffer[i] & 0xf0) >> 4) * 256; + tmp = (tmp ? tmp : 1) | 0x01000000; + lirc_buffer_write_1(&sz->outbuf, (char *)&tmp); + + check_buffer(); + tmp = (sz->int_in_buffer[i] & 0x0f) * 256; + tmp = tmp ? tmp : 1; + lirc_buffer_write_1(&sz->outbuf, (char *)&tmp); + } + } +#undef check_buffer +out: + spin_unlock_irqrestore(&sz->interrupt_lock, flags); + wake_up(&sz->outbuf.wait_poll); +} + + +/* LIRC */ +static int streamzap_use_inc(void *data) { + struct usb_streamzap *sz=(struct usb_streamzap *)data; + int retval=0; + + dbg("Entering streamzap_use_inc for minor %d", sz->plugin.minor); + MOD_INC_USE_COUNT; + if (down_interruptible(&sz->lock)) { + MOD_DEC_USE_COUNT; + dbg("streamzap_use_inc for minor %d returns -ERESTARTSYS", sz->plugin.minor); + return -ERESTARTSYS; + } + + if (!sz->udev) { + up(&sz->lock); + return -ENODEV; + } + + if (!sz->open_count++) { + sz->irq.dev = sz->udev; + if ((retval = usb_submit_urb(&sz->irq))) { + info("streamzap_use_inc(minor %d): usb_submit_urb returned %d", sz->plugin.minor, retval); + dbg("streamzap_use_inc for minor %d returns -EIO", sz->plugin.minor); + retval = -EIO; + goto fail; + } + } + dbg("streamzap_use_inc for minor %d success (open_count %u)", sz->plugin.minor, sz->open_count); + goto exit; + +fail: + MOD_DEC_USE_COUNT; +exit: + up(&sz->lock); + return retval; +} + +static void streamzap_use_dec(void *data) { + struct usb_streamzap *sz=(struct usb_streamzap *)data; + + dbg("Entering streamzap_use_dec for minor %d", sz->plugin.minor); + down(&sz->lock); + if (sz->open_count == 0) { + info("streamzap_use_dec called when use count is 0!"); + return; + } + + if (!--sz->open_count) usb_unlink_urb(&sz->irq); + + up(&sz->lock); + MOD_DEC_USE_COUNT; + + dbg("Exiting streamzap_use_dec for minor %d (open_count %u)", sz->plugin.minor, sz->open_count); +} + +/* Module functions */ +static int __init streamzap_init(void) +{ + int result; + + if (MAX_IRCTL_DEVICES < minor) { + err("Parameter minor (%d) must be less than %d!", + minor, MAX_IRCTL_DEVICES-1); + return -EINVAL; + } + + if ((result = usb_register(&streamzap_driver)) < 0) { + err("usb_register failed. Error number %d", result); + return -EINVAL; + } + + info(DRIVER_AUTHOR " " DRIVER_VERSION); + info(DRIVER_DESC); + + return 0; +} + +static void __exit streamzap_exit(void) +{ + usb_deregister(&streamzap_driver); + dbg("Exiting"); +} + +module_init(streamzap_init); +module_exit(streamzap_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff -Naur lirc-0.7.0pre7/remotes/streamzap/lircd.conf.streamzap lirc-0.7.0pre7-streamzap-0.07/remotes/streamzap/lircd.conf.streamzap --- lirc-0.7.0pre7/remotes/streamzap/lircd.conf.streamzap 1969-12-31 19:00:00.000000000 -0500 +++ lirc-0.7.0pre7-streamzap-0.07/remotes/streamzap/lircd.conf.streamzap 2004-08-06 13:40:27.000000000 -0400 @@ -0,0 +1,60 @@ +# brand: streamzap +# model no. of remote control: +# devices being controlled by this remote: +# + +begin remote + name streamzap + bits 6 + flags RC5 + eps 0 + aeps 384 + + one 768 768 + zero 768 768 + plead 768 + pre_data_bits 8 + pre_data 0xA3 + gap 65280 + toggle_bit 2 + + + begin codes + 0 0x00 + 1 0x01 + 2 0x02 + 3 0x03 + 4 0x04 + 5 0x05 + 6 0x06 + 7 0x07 + 8 0x08 + 9 0x09 + Power 0x0A + Mute 0x0B + ChUp 0x0C + VolUp 0x0D + ChDown 0x0E + VolDown 0x0F + Up 0x10 + Left 0x11 + OK 0x12 + Right 0x13 + Down 0x14 + Menu 0x15 + Exit 0x16 + Play 0x17 + Pause 0x18 + Stop 0x19 + TrackPrev 0x1A + TrackNext 0x1B + Record 0x1C + SeekBack 0x1D + SeekFw 0x1E + Red 0x20 + Green 0x21 + Yellow 0x22 + Blue 0x23 + end codes + +end remote diff -Naur lirc-0.7.0pre7/setup.data lirc-0.7.0pre7-streamzap-0.07/setup.data --- lirc-0.7.0pre7/setup.data 2004-07-24 11:01:25.000000000 -0400 +++ lirc-0.7.0pre7-streamzap-0.07/setup.data 2004-08-06 13:40:27.000000000 -0400 @@ -99,6 +99,7 @@ atiusb: "ATI/NVidia/X10 RF Remote" sasem: "Dign HV5 HTPC IR/VFD Module" tira: "Home Electronics Tira USB device" + streamzap: "StreamZap PC Remote (USB)" pcmak_usb: "PCMAK USB receiver" sasem: "Sasem OnAir Remocon-V" exaudio: "Sound Blaster Extigy USB sound card" @@ -125,7 +126,7 @@ hercules_smarttv_stereo it87 knc_one kworld leadtek_0007 \ leadtek_0010 livedrive_midi livedrive_seq mceusb \ mediafocusI none pixelview_bt878 pixelview_pak \ - pixelview_pro provideo sa1100 sasem tekram_bt829 tvbox udp + pixelview_pro provideo sa1100 sasem streamzap tekram_bt829 tvbox udp none: default_param: atiusb audio audio_alsa avermedia avermedia98 \ @@ -161,4 +162,3 @@ default_param: pcmak_usb tira ttyUSB1: -