<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.mediawiki.compulab.com/w/index.php?action=history&amp;feed=atom&amp;title=Lirc_igorplugusb.c</id>
	<title>Lirc igorplugusb.c - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.mediawiki.compulab.com/w/index.php?action=history&amp;feed=atom&amp;title=Lirc_igorplugusb.c"/>
	<link rel="alternate" type="text/html" href="https://www.mediawiki.compulab.com/w/index.php?title=Lirc_igorplugusb.c&amp;action=history"/>
	<updated>2026-05-03T10:20:54Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.31.0</generator>
	<entry>
		<id>https://www.mediawiki.compulab.com/w/index.php?title=Lirc_igorplugusb.c&amp;diff=622&amp;oldid=prev</id>
		<title>Denis at 15:39, 16 July 2009</title>
		<link rel="alternate" type="text/html" href="https://www.mediawiki.compulab.com/w/index.php?title=Lirc_igorplugusb.c&amp;diff=622&amp;oldid=prev"/>
		<updated>2009-07-16T15:39:36Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;This is a driver module for '''Infrared Receiver IgprPlug-USB (AVR)''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* lirc_igorplugusb - USB remote support for LIRC&lt;br /&gt;
 *&lt;br /&gt;
 * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.&lt;br /&gt;
 *&lt;br /&gt;
 * The device can only record bursts of up to 36 pulses/spaces.&lt;br /&gt;
 * Works fine with RC5.&lt;br /&gt;
 * (Maybe a better firmware or a microcontroller with more ram can help?)&lt;br /&gt;
 *&lt;br /&gt;
 *&lt;br /&gt;
 * Changelog:&lt;br /&gt;
 *   Denis Turischev    &amp;lt;denis@compulab.co.il&amp;gt;&lt;br /&gt;
 *   23.06.09 - Added circular buffer reading&lt;br /&gt;
 *&lt;br /&gt;
 * 2004 Jan M. Hochstein  &amp;lt;hochstein@algo.informatik.tu-darmstadt.de&amp;gt;&lt;br /&gt;
 *&lt;br /&gt;
 * This driver was derived from:&lt;br /&gt;
 *   Paul Miller &amp;lt;pmiller9@users.sourceforge.net&amp;gt;&lt;br /&gt;
 *      &amp;quot;lirc_atiusb&amp;quot; module&lt;br /&gt;
 *   Vladimir Dergachev &amp;lt;volodya@minspring.com&amp;gt;'s 2002&lt;br /&gt;
 *      &amp;quot;USB ATI Remote support&amp;quot; (input device)&lt;br /&gt;
 *   Adrian Dewhurst &amp;lt;sailor-lk@sailorfrag.net&amp;gt;'s 2002&lt;br /&gt;
 *      &amp;quot;USB StreamZap remote driver&amp;quot; (LIRC)&lt;br /&gt;
 *   Artur Lipowski &amp;lt;alipowski@kki.net.pl&amp;gt;'s 2002&lt;br /&gt;
 *      &amp;quot;lirc_dev&amp;quot; and &amp;quot;lirc_gpio&amp;quot; LIRC modules&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * This program is free software; you can redistribute it and/or modify&lt;br /&gt;
 * it under the terms of the GNU General Public License as published by&lt;br /&gt;
 * the Free Software Foundation; either version 2 of the License, or&lt;br /&gt;
 * (at your option) any later version.&lt;br /&gt;
 *&lt;br /&gt;
 * This program is distributed in the hope that it will be useful,&lt;br /&gt;
 * but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
 * GNU General Public License for more details.&lt;br /&gt;
 *&lt;br /&gt;
 * You should have received a copy of the GNU General Public License&lt;br /&gt;
 * along with this program; if not, write to the Free Software&lt;br /&gt;
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA&lt;br /&gt;
 *&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;linux/version.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/autoconf.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/kernel.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/kmod.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/sched.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/errno.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/ioctl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/fs.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/usb.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/poll.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/smp_lock.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;kcompat.h&amp;quot;&lt;br /&gt;
#include &amp;quot;lirc.h&amp;quot;&lt;br /&gt;
#include &amp;quot;lirc_dev/lirc_dev.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/* lock irctl structure */&lt;br /&gt;
#define IRLOCK			down_interruptible(&amp;amp;ir-&amp;gt;lock)&lt;br /&gt;
#define IRUNLOCK		up(&amp;amp;ir-&amp;gt;lock)&lt;br /&gt;
&lt;br /&gt;
/* module identification */&lt;br /&gt;
#define DRIVER_VERSION		&amp;quot;0.1&amp;quot;&lt;br /&gt;
#define DRIVER_AUTHOR		\&lt;br /&gt;
	&amp;quot;Jan M. Hochstein &amp;lt;hochstein@algo.informatik.tu-darmstadt.de&amp;gt;&amp;quot;&lt;br /&gt;
#define DRIVER_DESC		&amp;quot;USB remote driver for LIRC&amp;quot;&lt;br /&gt;
#define DRIVER_NAME		&amp;quot;lirc_igorplugusb&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/* debugging support */&lt;br /&gt;
#ifdef CONFIG_USB_DEBUG&lt;br /&gt;
static int debug = 1;&lt;br /&gt;
#else&lt;br /&gt;
static int debug;&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
#define dprintk(fmt, args...)					\&lt;br /&gt;
	do {							\&lt;br /&gt;
		if (debug)					\&lt;br /&gt;
			printk(KERN_DEBUG fmt, ## args);	\&lt;br /&gt;
	} while (0)&lt;br /&gt;
&lt;br /&gt;
/* general constants */&lt;br /&gt;
#define SUCCESS		 0&lt;br /&gt;
&lt;br /&gt;
/* One mode2 pulse/space has 4 bytes. */&lt;br /&gt;
#define CODE_LENGTH	     sizeof(lirc_t)&lt;br /&gt;
&lt;br /&gt;
/* Igor's firmware cannot record bursts longer than 36. */&lt;br /&gt;
#define DEVICE_BUFLEN	   36&lt;br /&gt;
&lt;br /&gt;
/** Header at the beginning of the device's buffer:&lt;br /&gt;
	unsigned char data_length&lt;br /&gt;
	unsigned char data_start    (!=0 means ring-buffer overrun)&lt;br /&gt;
	unsigned char counter       (incremented by each burst)&lt;br /&gt;
**/&lt;br /&gt;
#define DEVICE_HEADERLEN	3&lt;br /&gt;
&lt;br /&gt;
/* This is for the gap */&lt;br /&gt;
#define ADDITIONAL_LIRC_BYTES   2&lt;br /&gt;
&lt;br /&gt;
/* times to poll per second */&lt;br /&gt;
#define SAMPLE_RATE	     100&lt;br /&gt;
&lt;br /&gt;
static int sample_rate = SAMPLE_RATE;&lt;br /&gt;
&lt;br /&gt;
/**** Igor's USB Request Codes */&lt;br /&gt;
&lt;br /&gt;
#define SET_INFRABUFFER_EMPTY   1&lt;br /&gt;
/**&lt;br /&gt;
 * Params: none&lt;br /&gt;
 * Answer: empty&lt;br /&gt;
 *&lt;br /&gt;
**/&lt;br /&gt;
&lt;br /&gt;
#define GET_INFRACODE	   2&lt;br /&gt;
/**&lt;br /&gt;
 * Params:&lt;br /&gt;
 *   wValue: offset to begin reading infra buffer&lt;br /&gt;
 *&lt;br /&gt;
 * Answer: infra data&lt;br /&gt;
 *&lt;br /&gt;
**/&lt;br /&gt;
&lt;br /&gt;
/* data structure for each usb remote */&lt;br /&gt;
struct irctl {&lt;br /&gt;
&lt;br /&gt;
	/* usb */&lt;br /&gt;
	struct usb_device *usbdev;&lt;br /&gt;
	int devnum;&lt;br /&gt;
&lt;br /&gt;
	unsigned char *buf_in;&lt;br /&gt;
	unsigned int len_in;&lt;br /&gt;
	int in_space;&lt;br /&gt;
	struct timeval last_time;&lt;br /&gt;
&lt;br /&gt;
	dma_addr_t dma_in;&lt;br /&gt;
&lt;br /&gt;
	/* lirc */&lt;br /&gt;
	struct lirc_plugin *p;&lt;br /&gt;
&lt;br /&gt;
	/* handle sending (init strings) */&lt;br /&gt;
	wait_queue_head_t wait_out;&lt;br /&gt;
&lt;br /&gt;
	struct semaphore lock;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static int unregister_from_lirc(struct irctl *ir)&lt;br /&gt;
{&lt;br /&gt;
	struct lirc_plugin *p = ir-&amp;gt;p;&lt;br /&gt;
	int devnum;&lt;br /&gt;
&lt;br /&gt;
	if (!ir-&amp;gt;p)&lt;br /&gt;
		return -EINVAL;&lt;br /&gt;
&lt;br /&gt;
	devnum = ir-&amp;gt;devnum;&lt;br /&gt;
	dprintk(DRIVER_NAME &amp;quot;[%d]: unregister from lirc called\n&amp;quot;, devnum);&lt;br /&gt;
&lt;br /&gt;
	lirc_unregister_plugin(p-&amp;gt;minor);&lt;br /&gt;
&lt;br /&gt;
	printk(DRIVER_NAME &amp;quot;[%d]: usb remote disconnected\n&amp;quot;, devnum);&lt;br /&gt;
&lt;br /&gt;
	lirc_buffer_free(p-&amp;gt;rbuf);&lt;br /&gt;
	kfree(p-&amp;gt;rbuf);&lt;br /&gt;
	kfree(p);&lt;br /&gt;
	kfree(ir);&lt;br /&gt;
	ir-&amp;gt;p = NULL;&lt;br /&gt;
	return SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static int set_use_inc(void *data)&lt;br /&gt;
{&lt;br /&gt;
	struct irctl *ir = data;&lt;br /&gt;
&lt;br /&gt;
	if (!ir) {&lt;br /&gt;
		printk(DRIVER_NAME &amp;quot;[?]: set_use_inc called with no context\n&amp;quot;);&lt;br /&gt;
		return -EIO;&lt;br /&gt;
	}&lt;br /&gt;
	dprintk(DRIVER_NAME &amp;quot;[%d]: set use inc\n&amp;quot;, ir-&amp;gt;devnum);&lt;br /&gt;
&lt;br /&gt;
	MOD_INC_USE_COUNT;&lt;br /&gt;
&lt;br /&gt;
	if (!ir-&amp;gt;usbdev)&lt;br /&gt;
		return -ENODEV;&lt;br /&gt;
&lt;br /&gt;
	return SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void set_use_dec(void *data)&lt;br /&gt;
{&lt;br /&gt;
	struct irctl *ir = data;&lt;br /&gt;
&lt;br /&gt;
	if (!ir) {&lt;br /&gt;
		printk(DRIVER_NAME &amp;quot;[?]: set_use_dec called with no context\n&amp;quot;);&lt;br /&gt;
		return;&lt;br /&gt;
	}&lt;br /&gt;
	dprintk(DRIVER_NAME &amp;quot;[%d]: set use dec\n&amp;quot;, ir-&amp;gt;devnum);&lt;br /&gt;
&lt;br /&gt;
	MOD_DEC_USE_COUNT;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static void set_infrabuffer_empty(struct irctl *ir){&lt;br /&gt;
	int ret;	&lt;br /&gt;
	ret = usb_control_msg(ir-&amp;gt;usbdev, usb_rcvctrlpipe(ir-&amp;gt;usbdev, 0),&lt;br /&gt;
		SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR | USB_DIR_IN,&lt;br /&gt;
		0, 0, ir-&amp;gt;buf_in, ir-&amp;gt;len_in, HZ * USB_CTRL_GET_TIMEOUT);&lt;br /&gt;
	if (ret &amp;lt; 0)&lt;br /&gt;
		printk(DRIVER_NAME &amp;quot;[%d]: SET_INFRABUFFER_EMPTY: error %d\n&amp;quot;, ir-&amp;gt;devnum, ret);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Called in user context.&lt;br /&gt;
 * return 0 if data was added to the buffer and&lt;br /&gt;
 * -ENODATA if none was available. This should add some number of bits&lt;br /&gt;
 * evenly divisible by code_length to the buffer&lt;br /&gt;
**/&lt;br /&gt;
static int usb_remote_poll(void *data, struct lirc_buffer *buf)&lt;br /&gt;
{&lt;br /&gt;
	int ret, bytes_to_read, sequence_number, last_readed_index, i;&lt;br /&gt;
	struct irctl *ir = (struct irctl *)data;&lt;br /&gt;
&lt;br /&gt;
	if (!ir-&amp;gt;usbdev)  /* Has the device been removed? */&lt;br /&gt;
		return -ENODEV;&lt;br /&gt;
&lt;br /&gt;
	memset(ir-&amp;gt;buf_in, 0, DEVICE_HEADERLEN);&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
	ret = usb_control_msg(&lt;br /&gt;
	      ir-&amp;gt;usbdev, usb_rcvctrlpipe(ir-&amp;gt;usbdev, 0),&lt;br /&gt;
	      GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN,&lt;br /&gt;
	      0/* offset */, /*unused*/0,&lt;br /&gt;
	      ir-&amp;gt;buf_in, DEVICE_HEADERLEN,&lt;br /&gt;
	      /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
	if (ret == 1) {&lt;br /&gt;
		/* ACK packet has 1 byte --&amp;gt; ignore */&lt;br /&gt;
		return -ENODATA;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (ret != DEVICE_HEADERLEN) {&lt;br /&gt;
		printk(DRIVER_NAME &amp;quot;[%d]: CORRUPTED HEADER: length =  %d\n&amp;quot;, ir-&amp;gt;devnum, ret);&lt;br /&gt;
&lt;br /&gt;
		/* Try to recover from unexpected error */&lt;br /&gt;
		set_infrabuffer_empty(ir);&lt;br /&gt;
		ir-&amp;gt;in_space = 1;&lt;br /&gt;
&lt;br /&gt;
		return -ENODATA;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	bytes_to_read = ir-&amp;gt;buf_in[0];&lt;br /&gt;
	sequence_number = ir-&amp;gt;buf_in[1];&lt;br /&gt;
	last_readed_index = ir-&amp;gt;buf_in[2];&lt;br /&gt;
&lt;br /&gt;
	memset(ir-&amp;gt;buf_in, 0, ir-&amp;gt;len_in);&lt;br /&gt;
&lt;br /&gt;
	ret = usb_control_msg( ir-&amp;gt;usbdev, usb_rcvctrlpipe(ir-&amp;gt;usbdev, 0),&lt;br /&gt;
		GET_INFRACODE, USB_TYPE_VENDOR | USB_DIR_IN,&lt;br /&gt;
		DEVICE_HEADERLEN, 0, ir-&amp;gt;buf_in, bytes_to_read,HZ * USB_CTRL_GET_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
	if ((ret == bytes_to_read) &amp;amp;&amp;amp; (sequence_number != -1)) {&lt;br /&gt;
		lirc_t code, timediff;&lt;br /&gt;
		struct timeval now;&lt;br /&gt;
&lt;br /&gt;
		do_gettimeofday(&amp;amp;now);&lt;br /&gt;
		timediff = now.tv_sec - ir-&amp;gt;last_time.tv_sec;&lt;br /&gt;
		if (timediff + 1 &amp;gt; PULSE_MASK / 1000000)&lt;br /&gt;
			timediff = PULSE_MASK;&lt;br /&gt;
		else {&lt;br /&gt;
			timediff *= 1000000;&lt;br /&gt;
			timediff += now.tv_usec - ir-&amp;gt;last_time.tv_usec;&lt;br /&gt;
		}&lt;br /&gt;
		ir-&amp;gt;last_time.tv_sec = now.tv_sec;&lt;br /&gt;
		ir-&amp;gt;last_time.tv_usec = now.tv_usec;&lt;br /&gt;
&lt;br /&gt;
		/* create leading gap  */&lt;br /&gt;
		code = timediff;&lt;br /&gt;
		&lt;br /&gt;
		lirc_buffer_write_n(buf, (unsigned char *)&amp;amp;code, 1);&lt;br /&gt;
		ir-&amp;gt;in_space = 1;   /* next comes a pulse */&lt;br /&gt;
&lt;br /&gt;
		/* MODE2: pulse/space (PULSE_BIT) in 1us units */&lt;br /&gt;
&lt;br /&gt;
		for(i = last_readed_index; i &amp;lt; bytes_to_read; i++){&lt;br /&gt;
			/* 1 Igor-tick = 85.333333 us */&lt;br /&gt;
			code = (unsigned int)ir-&amp;gt;buf_in[i] * 85	+ (unsigned int)ir-&amp;gt;buf_in[i] / 3;&lt;br /&gt;
			ir-&amp;gt;last_time.tv_usec += code;&lt;br /&gt;
			if (ir-&amp;gt;in_space)&lt;br /&gt;
				code |= PULSE_BIT;&lt;br /&gt;
			lirc_buffer_write_n(buf, (unsigned char *)&amp;amp;code, 1);&lt;br /&gt;
			/* 1 chunk = CODE_LENGTH bytes */&lt;br /&gt;
			ir-&amp;gt;in_space ^= 1;&lt;br /&gt;
		}&lt;br /&gt;
		for(i = 0; i &amp;lt; last_readed_index - 1; i++){&lt;br /&gt;
			/* 1 Igor-tick = 85.333333 us */&lt;br /&gt;
			code = (unsigned int)ir-&amp;gt;buf_in[i] * 85	+ (unsigned int)ir-&amp;gt;buf_in[i] / 3;&lt;br /&gt;
			ir-&amp;gt;last_time.tv_usec += code;&lt;br /&gt;
			if (ir-&amp;gt;in_space)&lt;br /&gt;
				code |= PULSE_BIT;&lt;br /&gt;
			lirc_buffer_write_n(buf, (unsigned char *)&amp;amp;code, 1);&lt;br /&gt;
			/* 1 chunk = CODE_LENGTH bytes */&lt;br /&gt;
			ir-&amp;gt;in_space ^= 1;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		set_infrabuffer_empty(ir);&lt;br /&gt;
&lt;br /&gt;
		return SUCCESS;&lt;br /&gt;
	} else&lt;br /&gt;
		printk(DRIVER_NAME &amp;quot;[%d]: GET_INFRACODE: error %d\n&amp;quot;, ir-&amp;gt;devnum, ret);&lt;br /&gt;
&lt;br /&gt;
	return -ENODATA;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static int usb_remote_probe(struct usb_interface *intf,&lt;br /&gt;
				const struct usb_device_id *id)&lt;br /&gt;
{&lt;br /&gt;
	struct usb_device *dev = NULL;&lt;br /&gt;
	struct usb_host_interface *idesc = NULL;&lt;br /&gt;
	struct usb_host_endpoint *ep_ctl2;&lt;br /&gt;
&lt;br /&gt;
	struct irctl *ir = NULL;&lt;br /&gt;
	struct lirc_plugin *plugin = NULL;&lt;br /&gt;
	struct lirc_buffer *rbuf = NULL;&lt;br /&gt;
	int devnum, pipe, maxp, bytes_in_key;&lt;br /&gt;
	int minor = 0;&lt;br /&gt;
	char buf[63], name[128] = &amp;quot;&amp;quot;;&lt;br /&gt;
	int mem_failure = 0;&lt;br /&gt;
	&lt;br /&gt;
	dprintk(DRIVER_NAME &amp;quot;: usb probe called.\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	dev = interface_to_usbdev(intf);&lt;br /&gt;
&lt;br /&gt;
	idesc = intf-&amp;gt;cur_altsetting;&lt;br /&gt;
&lt;br /&gt;
	if (idesc-&amp;gt;desc.bNumEndpoints != 1)&lt;br /&gt;
		return -ENODEV;&lt;br /&gt;
	ep_ctl2 = idesc-&amp;gt;endpoint;&lt;br /&gt;
	if (((ep_ctl2-&amp;gt;desc.bEndpointAddress &amp;amp; USB_ENDPOINT_DIR_MASK)&lt;br /&gt;
	    != USB_DIR_IN)&lt;br /&gt;
	    || (ep_ctl2-&amp;gt;desc.bmAttributes &amp;amp; USB_ENDPOINT_XFERTYPE_MASK)&lt;br /&gt;
	    != USB_ENDPOINT_XFER_CONTROL)&lt;br /&gt;
		return -ENODEV;&lt;br /&gt;
	pipe = usb_rcvctrlpipe(dev, ep_ctl2-&amp;gt;desc.bEndpointAddress);&lt;br /&gt;
&lt;br /&gt;
	devnum = dev-&amp;gt;devnum;&lt;br /&gt;
	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));&lt;br /&gt;
&lt;br /&gt;
	bytes_in_key = CODE_LENGTH;&lt;br /&gt;
&lt;br /&gt;
	dprintk(DRIVER_NAME &amp;quot;[%d]: bytes_in_key=%d maxp=%d\n&amp;quot;,&lt;br /&gt;
		devnum, bytes_in_key, maxp);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	/* allocate kernel memory */&lt;br /&gt;
	mem_failure = 0;&lt;br /&gt;
	ir = kmalloc(sizeof(struct irctl), GFP_KERNEL);&lt;br /&gt;
	if (!ir) {&lt;br /&gt;
		mem_failure = 1;&lt;br /&gt;
		goto mem_failure_switch;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	memset(ir, 0, sizeof(struct irctl));&lt;br /&gt;
&lt;br /&gt;
	plugin = kmalloc(sizeof(struct lirc_plugin), GFP_KERNEL);&lt;br /&gt;
	if (!plugin) {&lt;br /&gt;
		mem_failure = 2;&lt;br /&gt;
		goto mem_failure_switch;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);&lt;br /&gt;
	if (!rbuf) {&lt;br /&gt;
		mem_failure = 3;&lt;br /&gt;
		goto mem_failure_switch;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (lirc_buffer_init(rbuf, bytes_in_key,&lt;br /&gt;
			DEVICE_BUFLEN+ADDITIONAL_LIRC_BYTES)) {&lt;br /&gt;
		mem_failure = 4;&lt;br /&gt;
		goto mem_failure_switch;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	ir-&amp;gt;buf_in = usb_buffer_alloc(dev,&lt;br /&gt;
			      DEVICE_BUFLEN,&lt;br /&gt;
			      GFP_ATOMIC, &amp;amp;ir-&amp;gt;dma_in);&lt;br /&gt;
&lt;br /&gt;
	if (!ir-&amp;gt;buf_in) {&lt;br /&gt;
		mem_failure = 5;&lt;br /&gt;
		goto mem_failure_switch;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	memset(plugin, 0, sizeof(struct lirc_plugin));&lt;br /&gt;
&lt;br /&gt;
	strcpy(plugin-&amp;gt;name, DRIVER_NAME &amp;quot; &amp;quot;);&lt;br /&gt;
	plugin-&amp;gt;minor = -1;&lt;br /&gt;
	plugin-&amp;gt;code_length = bytes_in_key*8; /* in bits */&lt;br /&gt;
	plugin-&amp;gt;features = LIRC_CAN_REC_MODE2;&lt;br /&gt;
	plugin-&amp;gt;data = ir;&lt;br /&gt;
	plugin-&amp;gt;rbuf = rbuf;&lt;br /&gt;
	plugin-&amp;gt;set_use_inc = &amp;amp;set_use_inc;&lt;br /&gt;
	plugin-&amp;gt;set_use_dec = &amp;amp;set_use_dec;&lt;br /&gt;
	plugin-&amp;gt;sample_rate = sample_rate;    /* per second */&lt;br /&gt;
	plugin-&amp;gt;add_to_buf = &amp;amp;usb_remote_poll;&lt;br /&gt;
#ifdef LIRC_HAVE_SYSFS&lt;br /&gt;
	plugin-&amp;gt;dev = &amp;amp;dev-&amp;gt;dev;&lt;br /&gt;
#endif&lt;br /&gt;
	plugin-&amp;gt;owner = THIS_MODULE;&lt;br /&gt;
&lt;br /&gt;
	init_MUTEX(&amp;amp;ir-&amp;gt;lock);&lt;br /&gt;
	init_waitqueue_head(&amp;amp;ir-&amp;gt;wait_out);&lt;br /&gt;
&lt;br /&gt;
	minor = lirc_register_plugin(plugin);&lt;br /&gt;
	if (minor &amp;lt; 0)&lt;br /&gt;
		mem_failure = 9;&lt;br /&gt;
&lt;br /&gt;
mem_failure_switch:&lt;br /&gt;
&lt;br /&gt;
	/* free allocated memory in case of failure */&lt;br /&gt;
	switch (mem_failure) {&lt;br /&gt;
	case 9:&lt;br /&gt;
		usb_buffer_free(dev, DEVICE_BUFLEN,&lt;br /&gt;
			ir-&amp;gt;buf_in, ir-&amp;gt;dma_in);&lt;br /&gt;
&lt;br /&gt;
	case 5:&lt;br /&gt;
		lirc_buffer_free(rbuf);&lt;br /&gt;
	case 4:&lt;br /&gt;
		kfree(rbuf);&lt;br /&gt;
	case 3:&lt;br /&gt;
		kfree(plugin);&lt;br /&gt;
	case 2:&lt;br /&gt;
		kfree(ir);&lt;br /&gt;
	case 1:&lt;br /&gt;
		printk(DRIVER_NAME &amp;quot;[%d]: out of memory (code=%d)\n&amp;quot;,devnum, mem_failure);&lt;br /&gt;
		return -ENOMEM;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	plugin-&amp;gt;minor = minor;&lt;br /&gt;
	ir-&amp;gt;p = plugin;&lt;br /&gt;
	ir-&amp;gt;devnum = devnum;&lt;br /&gt;
	ir-&amp;gt;usbdev = dev;&lt;br /&gt;
	ir-&amp;gt;len_in = DEVICE_BUFLEN;&lt;br /&gt;
	ir-&amp;gt;in_space = 1; /* First mode2 event is a space. */&lt;br /&gt;
	do_gettimeofday(&amp;amp;ir-&amp;gt;last_time);&lt;br /&gt;
&lt;br /&gt;
	if (dev-&amp;gt;descriptor.iManufacturer&lt;br /&gt;
		&amp;amp;&amp;amp; usb_string(dev, dev-&amp;gt;descriptor.iManufacturer, buf, 63) &amp;gt; 0)&lt;br /&gt;
		strncpy(name, buf, 128);&lt;br /&gt;
	if (dev-&amp;gt;descriptor.iProduct&lt;br /&gt;
		&amp;amp;&amp;amp; usb_string(dev, dev-&amp;gt;descriptor.iProduct, buf, 63) &amp;gt; 0)&lt;br /&gt;
		snprintf(name, 128, &amp;quot;%s %s&amp;quot;, name, buf);&lt;br /&gt;
	printk(DRIVER_NAME &amp;quot;[%d]: %s on usb%d:%d\n&amp;quot;, devnum, name,&lt;br /&gt;
	       dev-&amp;gt;bus-&amp;gt;busnum, devnum);&lt;br /&gt;
&lt;br /&gt;
	set_infrabuffer_empty(ir);&lt;br /&gt;
&lt;br /&gt;
	usb_set_intfdata(intf, ir);&lt;br /&gt;
	return SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
static void usb_remote_disconnect(struct usb_interface *intf)&lt;br /&gt;
{&lt;br /&gt;
	struct usb_device *dev = interface_to_usbdev(intf);&lt;br /&gt;
	struct irctl *ir = usb_get_intfdata(intf);&lt;br /&gt;
	usb_set_intfdata(intf, NULL);&lt;br /&gt;
&lt;br /&gt;
	if (!ir || !ir-&amp;gt;p)&lt;br /&gt;
		return;&lt;br /&gt;
&lt;br /&gt;
	ir-&amp;gt;usbdev = NULL;&lt;br /&gt;
	wake_up_all(&amp;amp;ir-&amp;gt;wait_out);&lt;br /&gt;
&lt;br /&gt;
	IRLOCK;&lt;br /&gt;
	usb_buffer_free(dev, ir-&amp;gt;len_in, ir-&amp;gt;buf_in, ir-&amp;gt;dma_in);&lt;br /&gt;
	IRUNLOCK;&lt;br /&gt;
&lt;br /&gt;
	unregister_from_lirc(ir);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static struct usb_device_id usb_remote_id_table [] = {&lt;br /&gt;
	/* Igor Plug USB (Atmel's Manufact. ID) */&lt;br /&gt;
	{ USB_DEVICE(0x03eb, 0x0002) },&lt;br /&gt;
	{ USB_DEVICE(0x03eb, 0x21fe) },&lt;br /&gt;
	/* Terminating entry */&lt;br /&gt;
	{ }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static struct usb_driver usb_remote_driver = {&lt;br /&gt;
	LIRC_THIS_MODULE(.owner = THIS_MODULE)&lt;br /&gt;
	.name =		DRIVER_NAME,&lt;br /&gt;
	.probe =	usb_remote_probe,&lt;br /&gt;
	.disconnect =	usb_remote_disconnect,&lt;br /&gt;
	.id_table =	usb_remote_id_table&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static int __init usb_remote_init(void)&lt;br /&gt;
{&lt;br /&gt;
	int i;&lt;br /&gt;
&lt;br /&gt;
	printk(KERN_INFO &amp;quot;\n&amp;quot;&lt;br /&gt;
	       DRIVER_NAME &amp;quot;: &amp;quot; DRIVER_DESC &amp;quot; v&amp;quot; DRIVER_VERSION &amp;quot;\n&amp;quot;);&lt;br /&gt;
	printk(DRIVER_NAME &amp;quot;: &amp;quot; DRIVER_AUTHOR &amp;quot;\n&amp;quot;);&lt;br /&gt;
	dprintk(DRIVER_NAME &amp;quot;: debug mode enabled\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	request_module(&amp;quot;lirc_dev&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	i = usb_register(&amp;amp;usb_remote_driver);&lt;br /&gt;
	if (i &amp;lt; 0) {&lt;br /&gt;
		printk(DRIVER_NAME &amp;quot;: usb register failed, result = %d\n&amp;quot;, i);&lt;br /&gt;
		return -ENODEV;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void __exit usb_remote_exit(void)&lt;br /&gt;
{&lt;br /&gt;
	usb_deregister(&amp;amp;usb_remote_driver);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
module_init(usb_remote_init);&lt;br /&gt;
module_exit(usb_remote_exit);&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;linux/vermagic.h&amp;gt;&lt;br /&gt;
MODULE_INFO(vermagic, VERMAGIC_STRING);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MODULE_DESCRIPTION(DRIVER_DESC);&lt;br /&gt;
MODULE_AUTHOR(DRIVER_AUTHOR);&lt;br /&gt;
MODULE_LICENSE(&amp;quot;GPL&amp;quot;);&lt;br /&gt;
MODULE_DEVICE_TABLE(usb, usb_remote_id_table);&lt;br /&gt;
&lt;br /&gt;
module_param(sample_rate, int, 0644);&lt;br /&gt;
MODULE_PARM_DESC(sample_rate, &amp;quot;Sampling rate in Hz (default: 100)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
EXPORT_NO_SYMBOLS;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Denis</name></author>
		
	</entry>
</feed>