Driver for usb remote control (pid 13ec, vid 000a)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello, the following is a driver for a usb remote control with product
id 13ec and vendor id 000a  (it came with a Asus tv card).  I'm
looking for comments and people to help test it.


Thank you

P.S. please CC me personally

/*
*      USB remote control driver
*
*      2006 Marc-Antoine Avon-Charreyron <[email protected]>
*
*      This driver is based on drivers/usb/usb-skeleton.c
*/

/*
*	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, version 2.
*/

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <asm/uaccess.h>
#include <linux/usb.h>


/* Define these values to match your devices */
#define USB_REMCTL_VENDOR_ID	0x13ec
#define USB_REMCTL_PRODUCT_ID	0x000a


/* table of devices that work with this driver */
static struct usb_device_id rem_ctl_table [] = {
	{ USB_DEVICE(USB_REMCTL_VENDOR_ID, USB_REMCTL_PRODUCT_ID) },
	{ }					/* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, rem_ctl_table);

/* Get a minor range for your devices from the usb maintainer */
#define USB_REMCTL_MINOR_BASE	192

struct semaphore sem;

/* Structure to hold all of our device specific stuff */
struct usb_rem_ctl {
	struct usb_device *	udev;			/* the usb device for this device */
	struct usb_interface *	interface;		/* the interface for this device */
	unsigned char *		data_in_buffer1;	/* the buffer to receive data from
endpoint 0x81*/
	unsigned char *		data_in_buffer2;        /* the buffer to receive
data from endpoint 0x82*/
	size_t			data_in_size;		/* the size of the receive buffer */
	struct kref		kref;
};
#define to_rem_ctl_dev(d) container_of(d, struct usb_rem_ctl, kref)

static struct usb_driver rem_ctl_driver;

static void rem_ctl_delete(struct kref *kref)
{	
	struct usb_rem_ctl *dev = to_rem_ctl_dev(kref);

	usb_put_dev(dev->udev);
	kfree (dev->data_in_buffer1);
	kfree (dev->data_in_buffer2);
	kfree (dev);
}

static void cb_read0(struct urb *urb, struct pt_regs *regs)
{
	usb_submit_urb(urb, GFP_ATOMIC);
	up(&sem);
}

static void cb_read1(struct urb *urb, struct pt_regs *regs)
{
	usb_submit_urb(urb, GFP_ATOMIC);
}

static int rem_ctl_open(struct inode *inode, struct file *file)
{
	struct usb_rem_ctl *dev;
	struct usb_interface *interface;
	int subminor;
	int retval = 0;

	subminor = iminor(inode);

	interface = usb_find_interface(&rem_ctl_driver, subminor);
	if (!interface) {
		err ("%s - error, can't find device for minor %d",
		     __FUNCTION__, subminor);
		retval = -ENODEV;
		goto exit;
	}

	dev = usb_get_intfdata(interface);
	if (!dev) {
		retval = -ENODEV;
		goto exit;
	}

	/* increment our usage count for the device */
	kref_get(&dev->kref);

	/* save our object in the file's private structure */
	file->private_data = dev;


	struct urb *urb;
	struct urb *urb2;
	urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!urb) {
		return -ENOMEM;
	}
	urb2 = usb_alloc_urb(0, GFP_KERNEL);
	if (!urb2) {
		return -ENOMEM;
	}

	usb_fill_int_urb(urb, dev->udev, usb_rcvintpipe(dev->udev, 0x81),
dev->data_in_buffer1,
dev->data_in_size, cb_read0, dev, 128);
	usb_fill_int_urb(urb2, dev->udev, usb_rcvintpipe(dev->udev, 0x82),
dev->data_in_buffer2, dev->data_in_size, cb_read1, dev, 128);

	retval = usb_submit_urb(urb, GFP_KERNEL);
	retval = usb_submit_urb(urb2, GFP_KERNEL);
	sema_init(&sem, 0);

exit:
	return retval;
}

static int rem_ctl_release(struct inode *inode, struct file *file)
{
	struct usb_rem_ctl *dev;

	dev = (struct usb_rem_ctl *)file->private_data;
	if (dev == NULL)
		return -ENODEV;

	/* decrement the count on our device */
	kref_put(&dev->kref, rem_ctl_delete);
	return 0;
}


static ssize_t read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
	struct usb_rem_ctl *dev;
	int retval = 0;

	char buf[1]="0";

	dev = (struct usb_rem_ctl *)file->private_data;

	down_interruptible(&sem);

	if((dev->data_in_buffer1[1] == 0x07) &&
	   (dev->data_in_buffer1[3] == 0x1f)) {                                   //TV

		buf[0] = 0x01;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x07) &&
		  (dev->data_in_buffer1[3] == 0x23)) {                            //FM
		
		buf[0] = 0x02;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x07) &&
		  (dev->data_in_buffer1[3] == 0x1e)) {                            //DVD
		
		buf[0] = 0x03;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x04) &&
   //Close
	          (dev->data_in_buffer1[3] == 0x3d)) {
		
		buf[0] = 0x04;
		retval = 1;

	} else if((dev->data_in_buffer1[1] == 0x03) &&                            //<<
	          (dev->data_in_buffer1[3] == 0x05)) {
		
		buf[0] = 0x05;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x01) &&
   //Stop
	          (dev->data_in_buffer1[3] == 0x16)) {
		
		buf[0] = 0x06;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x01) &&
   //Play/Pause
	          (dev->data_in_buffer1[3] == 0x13)) {
		
		buf[0] = 0x07;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x03) &&                            //>>
	          (dev->data_in_buffer1[3] == 0x09)) {
		
		buf[0] = 0x08;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x07) &&
   //don't know
	          (dev->data_in_buffer1[3] == 0x18)) {
		
		buf[0] = 0x09;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x01) &&
   //record
	          (dev->data_in_buffer1[3] == 0x15)) {
		
		buf[0] = 0x0a;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //pip
	          (dev->data_in_buffer1[3] == 0x1d)) {
		
		buf[0] = 0x0b;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //1
	          (dev->data_in_buffer1[3] == 0x1e)) {
		
		buf[0] = 0x0c;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //2
	          (dev->data_in_buffer1[3] == 0x1f)) {
		
		buf[0] = 0x0d;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //3
	          (dev->data_in_buffer1[3] == 0x20)) {
		
		buf[0] = 0x0e;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x01) &&
   //ch up
	          (dev->data_in_buffer1[3] == 0x09)) {
		
		buf[0] = 0x0f;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //4
	          (dev->data_in_buffer1[3] == 0x21)) {
		
		buf[0] = 0x10;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //5
	          (dev->data_in_buffer1[3] == 0x22)) {
		
		buf[0] = 0x11;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //6
	          (dev->data_in_buffer1[3] == 0x23)) {
		
		buf[0] = 0x12;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x01) &&
   //ch down
	          (dev->data_in_buffer1[3] == 0x05)) {
		
		buf[0] = 0x13;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //7
	          (dev->data_in_buffer1[3] == 0x24)) {
		
		buf[0] = 0x14;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //8
	          (dev->data_in_buffer1[3] == 0x25)) {
		
		buf[0] = 0x15;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //9
	          (dev->data_in_buffer1[3] == 0x26)) {
		
		buf[0] = 0x16;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&
   //Back
	          (dev->data_in_buffer1[3] == 0x2a)) {
		
		buf[0] = 0x17;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //0
	          (dev->data_in_buffer1[3] == 0x27)) {
		
		buf[0] = 0x18;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&                            //up
	          (dev->data_in_buffer1[3] == 0x52)) {
		
		buf[0] = 0x1c;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&
   //right
	          (dev->data_in_buffer1[3] == 0x4f)) {
		
		buf[0] = 0x1d;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&
   //down
	          (dev->data_in_buffer1[3] == 0x51)) {
		
		buf[0] = 0x1e;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&
   //left
	          (dev->data_in_buffer1[3] == 0x50)) {
		
		buf[0] = 0x1f;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&
   //enter
	          (dev->data_in_buffer1[3] == 0x28)) {
		
		buf[0] = 0x20;
		retval = 1;
		
	} else if((dev->data_in_buffer1[1] == 0x00) &&
   //Volumes
	          (dev->data_in_buffer1[3] == 0x00)) {

		if(dev->data_in_buffer2[1] == 0x04) {           //Vol Down
			buf[0] = 0x19;
			retval = 1;
		} else if(dev->data_in_buffer2[1] == 0x02) {    //Vol Up
			buf[0] = 0x1a;
			retval = 1;
		} else if(dev->data_in_buffer2[1] == 0x01) {    //Mute
			buf[0] = 0x1b;
			retval = 1;
		}
		
	} else {
		return 0;
	}

	if (copy_to_user(buffer, buf, sizeof(buffer))) {
		retval = -EFAULT;
	}

	return retval;
}

static struct file_operations rem_ctl_fops = {
	.owner =	THIS_MODULE,
	.read =		read,
	.open =		rem_ctl_open,
	.release =	rem_ctl_release,
};

/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with devfs and the driver core
*/
static struct usb_class_driver rem_ctl_class = {
	.name =		"usb/remote%d",
	.fops =		&rem_ctl_fops,
	.minor_base =	USB_REMCTL_MINOR_BASE,
};

static int rem_ctl_probe(struct usb_interface *interface, const struct
usb_device_id *id)
{
	
	struct usb_rem_ctl *dev = NULL;
	struct usb_host_interface *iface_desc;
	struct usb_endpoint_descriptor *endpoint;
	size_t buffer_size;
	int retval = -ENOMEM;
	
	/* allocate memory for our device state and initialize it */
	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
	if (dev == NULL) {
		err("Out of memory");
		goto error;
	}
	memset(dev, 0x00, sizeof(*dev));
	kref_init(&dev->kref);

	dev->udev = usb_get_dev(interface_to_usbdev(interface));
	dev->interface = interface;

	/* set up the endpoint information */
	iface_desc = interface->cur_altsetting;
	endpoint = &iface_desc->endpoint[0].desc;

	buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
	dev->data_in_size = buffer_size;
	dev->data_in_buffer1 = kmalloc(buffer_size, GFP_KERNEL);
	if (!dev->data_in_buffer1) {
		err("Could not allocate data_in_buffer1");
		goto error;
	}
	dev->data_in_buffer2 = kmalloc(buffer_size, GFP_KERNEL);
	if (!dev->data_in_buffer2) {
		err("Could not allocate data_in_buffer2");
		goto error;
	}

	/* save our data pointer in this interface device */
	usb_set_intfdata(interface, dev);

	/* we can register the device now, as it is ready */
	retval = usb_register_dev(interface, &rem_ctl_class);
	if (retval) {
		/* something prevented us from registering this driver */
		err("Not able to get a minor for this device.");
		usb_set_intfdata(interface, NULL);
		goto error;
	}

	/* let the user know what node this device is now attached to */
	info("USB remote control device now attached to USBrem-%d", interface->minor);
		return 0;

	error:
		if (dev)
			kref_put(&dev->kref, rem_ctl_delete);
		return retval;
}

static void rem_ctl_disconnect(struct usb_interface *interface)
{
	struct usb_rem_ctl *dev;
	int minor = interface->minor;

	/* prevent rem_open() from racing rem_disconnect() */
	lock_kernel();

	dev = usb_get_intfdata(interface);
	usb_set_intfdata(interface, NULL);

	/* give back our minor */
	usb_deregister_dev(interface, &rem_ctl_class);

	unlock_kernel();

	/* decrement our usage count */
	kref_put(&dev->kref, rem_ctl_delete);

	info("USB remote #%d now disconnected", minor);
}

static struct usb_driver rem_ctl_driver = {
	.name =		"remote",
	.probe =	rem_ctl_probe,
	.disconnect =	rem_ctl_disconnect,
	.id_table =	rem_ctl_table,

};

static int __init usb_rem_ctl_init(void)
{
	int result;

	/* register this driver with the USB subsystem */
	result = usb_register(&rem_ctl_driver);
	if (result)
		err("usb_register failed. Error number %d", result);

	return result;
}

static void __exit usb_rem_ctl_exit(void)
{
	/* deregister this driver with the USB subsystem */
	usb_deregister(&rem_ctl_driver);
}

module_init (usb_rem_ctl_init);
module_exit (usb_rem_ctl_exit);

MODULE_LICENSE("GPL");
-
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/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux