Hi,

I'm trying to reverse-engineer a USB remote control receiver. 
Fortunately the receiver consists of 1 configuration/1 interface/1
interrupt-input endpoint, and no additional setting is required to read
remote control signals from it.

First I used libusb to read input and I succeded.  With libusb, I just
open the device and usb_bulk_read() to read data.  But when I tried to
write a kernel driver, I failed.  The interrupt routine registered with
FILL_INT_URB() has never been called.

What is the difference between these?  I'm mostly sure that the kernel
driver was correct, because I copied code from the working driver
(streamzap remocon driver at http://sf.net/projects/szremote).

The sources of the libusb test program and kernel driver were attached.

Here is the /proc/bus/usb/devices entry:

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  6 Spd=1.5 MxCh= 0
D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=04e8 ProdID=ff30 Rev= 0.14
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
I:  If#= 1 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=10 Prot=ff Driver=usbdevfs
E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=10ms


Regards,
-- 
Changwoo Ryu <[EMAIL PROTECTED]>
#include <stdio.h>
#include <stdlib.h>
#include <usb.h>

struct usb_device *dev;
usb_dev_handle *dev_handle;
int ep_address;

static void dump_input(void)
{
	unsigned char buffer[256];
	int len, i;
	while (1) {
		len = usb_bulk_read(dev_handle, ep_address, buffer, 8, 10000);
		if (len <= 0)
			continue;
		if (buffer[7] == 255)
			continue;
#if 0
		if (buffer[7] == 1)
			continue;
		if (buffer[1] == 255 &&
		    buffer[2] == 255 &&
		    buffer[3] == 255 &&
		    buffer[4] == 255)
			continue;
#endif
		if (buffer[7] == 1)
			printf("------------------------------\n");
		for (i = 0; i < len; i++) {
			printf("%02X ", buffer[i]);
		}
		printf("\n");
	}
}
	

int
main(int argc, char *argv[])
{
	struct usb_bus *busses, *bus;
	usb_init();
	usb_find_busses();
	usb_find_devices();
	busses = usb_get_busses();

	for (bus = busses; bus; bus = bus->next) {
		for (dev = bus->devices; dev; dev = dev->next) {
			if (dev->descriptor.idVendor == 0x04e8 &&
			    dev->descriptor.idProduct == 0xff30) {
				goto found_dev;
			}
		}
	}

	exit(0);
 found_dev:
	dev_handle = usb_open(dev);
	usb_set_configuration(dev_handle, 1);
	usb_claim_interface(dev_handle, 1);
	ep_address = dev->config->interface->altsetting->endpoint->bEndpointAddress;
	usb_resetep(dev_handle, ep_address);
	dump_input();	
	usb_release_interface(dev_handle, 1);
	usb_close(dev_handle);
	exit(0);
}

/*
 * Local Variables:
 * mode: linux-c
 * End:
 */
/* lirc_imon - USB Soundgraph iMON remote driver
 * based on USB streamzap remote driver by Adrian Dewhurst
 * 
 * Copyright (C) 2002-2003 Adrian Dewhurst <[EMAIL PROTECTED]>
 * Copyright (C) 2003 Changwoo Ryu
 * 
 * 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, 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
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/slab.h>

static int debug = 1;

#define DRIVER_VERSION "v0.01"
#define DRIVER_AUTHOR "Changwoo Ryu, <[EMAIL PROTECTED]>"
#define DRIVER_DESC "lirc USB Soundgraph iMON remote driver"
#define USB_IMON_VENDOR_ID 0x04e8 /* Samsung Electronics? */
#define USB_IMON_PRODUCT_ID 0xff30

static struct usb_device_id imon_table[] = {
	{ USB_DEVICE(USB_IMON_VENDOR_ID, USB_IMON_PRODUCT_ID) },
	{ }			/* Terminating entry */
};

MODULE_DEVICE_TABLE(usb, imon_table);

struct usb_imon {
	struct usb_device *udev;  /* usb device struct; NULL upon disconnect */
#if 0
	struct lirc_plugin plugin; /* our lirc_dev device info */
#endif
	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;
#if 0
	struct lirc_buffer outbuf; /* kernel space -> user space buffer */
#endif
	spinlock_t interrupt_lock;

	unsigned int open_count;

	struct semaphore lock;   /* locks this structure */	
};

/* USB functions */
static void imon_irq(struct urb *urb);
static void * imon_probe(struct usb_device *dev, unsigned intf, const struct usb_device_id *id);
static void imon_disconnect(struct usb_device *dev, void *data);

static struct usb_driver imon_driver = {
	owner: THIS_MODULE,
	name: "lirc_imon",
	probe: imon_probe,
	disconnect: imon_disconnect,
	id_table: imon_table,
};

/* LIRC functions */
#if 0
static struct lirc_plugin imon_lirc_template = {
	minor: -1,
	sample_rate: 0,
	code_length: 32,
	features: LIRC_CAN_REC_MODE2,
	data: NULL,
	rbuf: NULL,
	set_use_inc: imon_use_inc,
	set_use_dec: imon_use_dec,
};
#endif

static void * imon_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_imon *imon = NULL;
	int pipe;

	/* 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_IMON_VENDOR_ID) ||
	    (dev->descriptor.idProduct != USB_IMON_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 (!(imon = kmalloc(sizeof(*imon), GFP_KERNEL))) {
		err("Out of memory allocating iMON device");
		return NULL;
	}
	memset(imon, 0, sizeof(*imon));

	/* Initialize locks and data */
	imon->udev = dev;
	init_MUTEX(&imon->lock);
	spin_lock_init(&imon->interrupt_lock);
	
	/* Allocate the URB buffer */
	imon->int_in_size = 128;
	if (!(imon->int_in_buffer = kmalloc(imon->int_in_size, GFP_KERNEL))) {
		err("Out of memory allocating imon interrupt buffer");
		goto error;
	}
	FILL_INT_URB(&imon->irq, dev, pipe, imon->int_in_buffer, imon->int_in_size, imon_irq, imon, endpoint->bInterval);

	goto exit;

 error:
	kfree(imon);
	imon = NULL;
 exit:
	return imon;
}

static void imon_disconnect(struct usb_device *dev, void *data)
{
	struct usb_imon *imon = (struct usb_imon*)data;
	imon->udev = NULL;
	kfree(imon);
}

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 imon_irq(struct urb *urb)
{
	struct usb_imon *imon = urb->context;

	printk("imon_irq called\n");
	if (urb->status) return;
	if (urb->actual_length == 0) return;
	if (!imon) {
		dbg("imon_irq called with no context");
		usb_unlink_urb(urb);
		return;
	}
	
	usb_streamzap_debug_data(__FUNCTION__, urb->actual_length, urb->transfer_buffer);
}

static int __init imon_init(void)
{
	int result;
	if ((result = usb_register(&imon_driver)) < 0) {
 		err("usb_register failed. Error number %d", result);
		return -EINVAL;
	}

	return 0;
}

static void __exit imon_exit(void)
{
	usb_deregister(&imon_driver);
	dbg("Exiting");
}
	

module_init(imon_init);
module_exit(imon_exit);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

/*
 * Local Variables:
 * mode: c
 * c-default-style: "k&r"
 * c-basic-offset: 8
 * indent-tabs-mode: t
 * End:
 */

Reply via email to