Just an FYI for those of us who bought one of the
updated MCE remotes and receivers. I was checking out
the lirc mailing list and someone has update the
driver to include support. From what I can tell the
update has not been updated in CVS.

I found the info at:
http://search.gmane.org/?query=mce&group=gmane.comp.hardware.lirc

Basically what I did was overwrite the lirc_mceusb.c
in the drivers/lirc_mceusb directory with the source
found in the mailing liste. (I have attached the new
source file.) Then went through the install process
documented. I used version .7.0 of lirc.

Please note, from what I have read and experienced,
there are some initialization problems. What seemed to
"fix it" was unplugging the receiver and plugging it
back in, until I no longer got an error message
stating the device did not initialize. You can check
this by running "tail -f /var/log/messages". Also, I
read that running kernel 2.6.11 seemed to fix the
initialization problem. However I cannot confirm this
as I am running Gentoo Dev Kernel 2.6.9-r9. Another
problem I am having is that I am getting non-stop
error messages stating:

"usb 2-2: bulk timeout on ep1in"

In fact, I was getting about 4 of those messages per
second. If/when I get time I am planning to upgrade to
2.6.11 to see if this fixes the issue.

-joe

--- Jim Oltman <[EMAIL PROTECTED]> wrote:
> After deleting the section in my rc.local about the
> mknod /dev/lirc0 c
> 61 0 and replacing it with:
> 
> ln -s /dev/lircd /dev/lirc0
> 
> I am no longer getting errors from lircd in the
> /var/log/messages. 
> IRW runs but I am not seeing anything when I press
> buttons on my
> Hauppauge remote (it has also been setup in the
> correct lircrc files).
>  When I run irrecord I am getting errors about lircd
> not being
> started.  I am going to try commenting out the other
> section in
> rc.local pertaining to MCEUSB and see what happens.
> 
> 
> On Sun, 13 Mar 2005 18:57:27 -0600, Jim Oltman
> <[EMAIL PROTECTED]> wrote:
> > Here is where I am at so far.  In my
> /etc/rc.d/rc.local I made these changes...
> > 
> > #!/bin/sh
> > #
> > # This script will be executed *after* all the
> other init scripts.
> > # You can put your own initialization stuff in
> here if you don't
> > # want to do the full Sys V style init stuff.
> > 
> > touch /var/lock/subsys/local
> > mknod /dev/lirc0 c 61 0 -------------I added this
> line in hopes it
> > would attach to a line in my modprobe
> > 
> > /usr/X11R6/bin/xset -dpms
> > /usr/X11R6/bin/xset s off
> > /usr/bin/mtd --daemon
> > 
> > # I added these next two lines
> > 
> > /sbin/modprobe lirc_mceusb
> > /usr/sbin/lircd --device=/dev/lirc0
> --output=/dev/lircd
> > 
> > In my /etc/modprobe.conf I have added this line:
> > 
> > alias char-major-61 lirc_mceusb
> > 
> > After implementing these changes, I can do a cat
> /var/log/messages and
> > see what I showed you before about the driver
> being loaded for the USB
> > Microsoft IR Transceiver.  But I also get this
> listed:
> > 
> > Mar 13 18:54:11 mythfrontend lircd 0.7.0[4134]:
> accepted new client on
> > /dev/lircd
> > Mar 13 18:54:11 mythfrontend lircd 0.7.0[4134]:
> could not open /dev/lirc0
> > Mar 13 18:54:11 mythfrontend lircd 0.7.0[4134]:
> default_init(): No such device
> > Mar 13 18:54:11 mythfrontend lircd 0.7.0[4134]:
> caught signal
> > 
> > I am however getting errors on boot in the
> Show/Hide Details window.
> > Where can I view the errors that it is showing me?
>  They disappear to
> > quickly to read.  I am pretty sure the info I want
> to see (about the
> > errors on boot in Show/Hide window) is not listed
> in
> > /var/log/messages.
> > 
> > On Sun, 13 Mar 2005 18:38:09 -0600, Ron Johnson
> <[EMAIL PROTECTED]> wrote:
> > > On Sun, 2005-03-13 at 17:58 -0600, Jim Oltman
> wrote:
> > > > What I meant in that statement is that I got
> it to recognize the
> > > > receiver in the /var/log/messages but it is
> still not working.
> > >
> > > Yes, but *how* did you get "it" to recognize the
> receiver?
> > >
> > > P.S. - Please do not erase the whole text of the
> email you are
> > > replying to.  That makes it quite difficult to
> follow the thread.
> > >
> > > --
> > >
>
-----------------------------------------------------------------
> > > Ron Johnson, Jr.
> > > Jefferson, LA USA
> > > PGP Key ID 8834C06B I prefer encrypted mail.
> > >
> > > Legality/morality of using open wireless points:
> > > "If I leave my door unlocked are you going to
> come into my house
> > > in the middle of the night because you need to
> use the restroom?
> > > I pay a fixed rate for water. It's cold water so
> there is no
> > > electricity usage. No financial loss. I have 2.5
> bathrooms, so no
> > > loss of usage on my end. Is this OK? Please, try
> this and we'll
> > > see if it's OK."
> > >
>
http://www.warchalking.org/comments/2002/9/22/223831/236/135
> > >
> > >
> > > _______________________________________________
> > > mythtv-users mailing list
> > > [email protected]
> > >
>
http://mythtv.org/cgi-bin/mailman/listinfo/mythtv-users
> > >
> > >
> > >
> > >
> >
> > _______________________________________________
> mythtv-users mailing list
> [email protected]
>
http://mythtv.org/cgi-bin/mailman/listinfo/mythtv-users
> 

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 
/*
 * USB Microsoft IR Transceiver driver - 0.2
 *
 * Copyright (c) 2003-2004 Dan Conti ([EMAIL PROTECTED])
 *
 * This driver is based on the USB skeleton driver packaged with the
 * kernel, and the notice from that package has been retained below.
 *
 * The Microsoft IR Transceiver is a neat little IR receiver with two
 * emitters on it designed for Windows Media Center. This driver might
 * work for all media center remotes, but I have only tested it with
 * the philips model. The first revision of this driver only supports
 * the receive function - the transmit function will be much more
 * tricky due to the nature of the hardware. Microsoft chose to build
 * this device inexpensively, therefore making it extra dumb.
 * There is no interrupt endpoint on this device; all usb traffic
 * happens over two bulk endpoints. As a result of this, poll() for
 * this device is an actual hardware poll (instead of a receive queue
 * check) and is rather expensive.
 *
 * All trademarks property of their respective owners. This driver was
 * originally based on the USB skeleton driver, although significant
 * portions of that code have been removed as the driver has evolved.
 *
 * 2003_11_11 - Restructured to minimalize code interpretation in the
 *              driver. The normal use case will be with lirc.
 *
 * 2004_01_01 - Removed all code interpretation. Generate mode2 data
 *              for passing off to lirc. Cleanup
 *
 * 2004_01_04 - Removed devfs handle. Put in a temporary workaround
 *              for a known issue where repeats generate two
 *              sequential spaces (last_was_repeat_gap)
 *
 * 2004_02_17 - Changed top level api to no longer use fops, and
 *              instead use new interface for polling via
 *              lirc_thread. Restructure data read/mode2 generation to
 *              a single pass, reducing number of buffers. Rev to .2
 *
 * 2004_02_27 - Last of fixups to plugin->add_to_buf API. Properly
 *              handle broken fragments from the receiver. Up the
 *              sample rate and remove any pacing from
 *              fetch_more_data. Fixes all known issues.
 *
 * 2005_02_17 - Updated to support new Phillips remote.
 * 
 * TODO
 *   - Fix up minor number, registration of major/minor with usb subsystem
 *
 */
/*
 * USB Skeleton driver - 1.1
 *
 * Copyright (C) 2001-2003 Greg Kroah-Hartman ([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, version 2.
 *
 *
 * This driver is to be used as a skeleton driver to be able to create a
 * USB driver quickly.  The design of it is based on the usb-serial and
 * dc2xx drivers.
 *
 * Thanks to Oliver Neukum, David Brownell, and Alan Stern for their help
 * in debugging this driver.
 *
 *
 * History:
 *
 * 2003-05-06 - 1.1 - changes due to usb core changes with usb_register_dev()
 * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and
 *                      disconnect.  Fix transfer amount in read().  Use
 *                      macros instead of magic numbers in probe().  Change
 *                      size variables to size_t.  Show how to eliminate
 *                      DMA bounce buffer.
 * 2002_12_12 - 0.9 - compile fixes and got rid of fixed minor array.
 * 2002_09_26 - 0.8 - changes due to USB core conversion to struct device
 *                      driver.
 * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do
 *                      not have both a bulk in and bulk out endpoint.
 *                      Thanks to Holger Waechtler for the fix.
 * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect.
 *                      Thanks to Pete Zaitcev for the fix.
 * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux
 * 2001_08_21 - 0.4 - more small bug fixes.
 * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel
 * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people
 * 2001_05_01 - 0.1 - first version
 *
 */

#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/smp_lock.h>
#include <linux/usb.h>
#ifdef KERNEL_2_5
#include <linux/completion.h>
#include <asm/uaccess.h>
#else
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/signal.h>
#endif

#ifdef CONFIG_USB_DEBUG
        static int debug = 1;
#else
        static int debug = 0;
#endif

#include "drivers/kcompat.h"
#include "drivers/lirc.h"
#include "drivers/lirc_dev/lirc_dev.h"

/* Use our own dbg macro */
#define dprintk(fmt, args...)                             \
        do{                                               \
                if(debug) printk(KERN_DEBUG __FILE__ ": " \
                                 fmt "\n", ## args);      \
        }while(0)

/* Version Information */
#define DRIVER_VERSION "v0.2"
#define DRIVER_AUTHOR "Dan Conti, [EMAIL PROTECTED]"
#define DRIVER_DESC "USB Microsoft IR Transceiver Driver"
#define DRIVER_NAME "lirc_mceusb"

/* IDs for old and new products */
#define USB_MCEUSB_VENDOR_ID1   0x045e
#define USB_MCEUSB_PRODUCT_ID1  0x006d
#define USB_MCEUSB_VENDOR_ID2   0x0471
#define USB_MCEUSB_PRODUCT_ID2  0x0815

/* table of devices that work with this driver */
static struct usb_device_id mceusb_table [] = {
        { USB_DEVICE(USB_MCEUSB_VENDOR_ID1, USB_MCEUSB_PRODUCT_ID1) },
        { USB_DEVICE(USB_MCEUSB_VENDOR_ID2, USB_MCEUSB_PRODUCT_ID2) },
        { } /* Terminating entry */
};

/* we can have up to this number of device plugged in at once */
#define MAX_DEVICES             16

/* Structure to hold all of our device specific stuff */
struct usb_skel {
        struct usb_device *         udev;               /* save off the usb 
device pointer */
        struct usb_interface *  interface;              /* the interface for 
this device */
        unsigned char   minor;                          /* the starting minor 
number for this device */
        unsigned char   num_ports;                      /* the number of ports 
this device has */
        char            num_interrupt_in;               /* number of interrupt 
in endpoints we have */
        char            num_bulk_in;                    /* number of bulk in 
endpoints we have */
        char            num_bulk_out;                   /* number of bulk out 
endpoints we have */

        unsigned char *    bulk_in_buffer;              /* the buffer to 
receive data */
        int                bulk_in_size;                /* the size of the 
receive buffer */
        __u8               bulk_in_endpointAddr;        /* the address of the 
bulk in endpoint */

        unsigned char *    bulk_out_buffer;             /* the buffer to send 
data */
        int                    bulk_out_size;           /* the size of the send 
buffer */
        struct urb *       write_urb;                   /* the urb used to send 
data */
        __u8               bulk_out_endpointAddr;       /* the address of the 
bulk out endpoint */

        atomic_t                write_busy;             /* true iff write urb 
is busy */
        struct completion       write_finished;         /* wait for the write 
to finish */
        
        wait_queue_head_t  wait_q;                      /* for timeouts */
        int                open_count;                  /* number of times this 
port has been opened */
        struct semaphore   sem;                         /* locks this structure 
*/
        
        int                     present;                /* if the device is not 
disconnected */         

        struct lirc_plugin* plugin;
        
        lirc_t lircdata[256];                           /* place to store 
values until lirc processes them */
        int    lircidx;                                 /* current index */
        int    lirccnt;                                 /* remaining values */
        
        int    usb_valid_bytes_in_bulk_buffer;          /* leftover data from a 
previous read */
        int    mce_bytes_left_in_packet;                /* for packets split 
across multiple reads */
        
        int    header_bytes;    /* Older remote sends 2-byte header */
        int    remote_type;             /* 1 for older remotes, 2 for newer */
        
        /* Value to hold the last received space; 0 if last value
         * received was a pulse
         */
        int    last_space;
        
#ifdef KERNEL_2_5
        dma_addr_t dma_in;
        dma_addr_t dma_out;
#endif
};

#define MCE_TIME_UNIT 50

/* driver api */
#ifdef KERNEL_2_5
static int mceusb_probe         (struct usb_interface *interface, const struct 
usb_device_id *id);
static void mceusb_disconnect   (struct usb_interface *interface);
static void mceusb_write_bulk_callback  (struct urb *urb, struct pt_regs *regs);
#else
static void * mceusb_probe      (struct usb_device *dev, unsigned int ifnum, 
const struct usb_device_id *id);
static void mceusb_disconnect   (struct usb_device *dev, void *ptr);
static void mceusb_write_bulk_callback  (struct urb *urb);
#endif

/* read data from the usb bus; convert to mode2 */
static int msir_fetch_more_data( struct usb_skel* dev, int dont_block );

/* helper functions */
static void msir_cleanup( struct usb_skel* dev );
static void set_use_dec( void* data );
static int set_use_inc( void* data );

/* array of pointers to our devices that are currently connected */
static struct usb_skel          *minor_table[MAX_DEVICES];

/* lock to protect the minor_table structure */
static DECLARE_MUTEX (minor_table_mutex);
static void mceusb_setup1( struct usb_device *udev );
static void mceusb_setup2( struct usb_device *udev, struct usb_skel* dev );

/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver mceusb_driver = {
        .owner =        THIS_MODULE,
        .name =         DRIVER_NAME,
        .probe =        mceusb_probe,
        .disconnect =   mceusb_disconnect,
        .id_table =     mceusb_table,
};

/**
 *      usb_mceusb_debug_data
 */
static inline void usb_mceusb_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(KERN_DEBUG "%.2x ", data[i]);
        }
        printk(KERN_DEBUG "\n");
}

/**
 *mceusb_delete
 */
static inline void mceusb_delete (struct usb_skel *dev)
{
        dprintk("%s", __func__);
        minor_table[dev->minor] = NULL;
#ifdef KERNEL_2_5
        usb_buffer_free(dev->udev, dev->bulk_in_size, dev->bulk_in_buffer, 
dev->dma_in);
        usb_buffer_free(dev->udev, dev->bulk_out_size, dev->bulk_out_buffer, 
dev->dma_out);
#else
        if (dev->bulk_in_buffer != NULL)
                kfree (dev->bulk_in_buffer);
        if (dev->bulk_out_buffer != NULL)
                kfree (dev->bulk_out_buffer);
#endif
        if (dev->write_urb != NULL)
                usb_free_urb (dev->write_urb);
        kfree (dev);
}

/* Setup routine for older MS remote */
static void mceusb_setup1( struct usb_device *udev )
{
        char data[8];
        int res;
        
        memset( data, 0, 8 );

        /* Get Status */
        res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              USB_REQ_GET_STATUS, USB_DIR_IN,
                              0, 0, data, 2, HZ * 3);

        /*    res = usb_get_status( udev, 0, 0, data ); */
        dprintk("%s - res = %d status = 0x%x 0x%x", __func__,
                res, data[0], data[1]);

        /* This is a strange one. They issue a set address to the device
         * on the receive control pipe and expect a certain value pair back
         */
        memset( data, 0, 8 );

        res = usb_control_msg( udev, usb_rcvctrlpipe(udev, 0),
                               5, USB_TYPE_VENDOR, 0, 0,
                               data, 2, HZ * 3 );
        dprintk("%s - res = %d, devnum = %d", __func__, res, udev->devnum);
        dprintk("%s - data[0] = %d, data[1] = %d", __func__,
                data[0], data[1] );

        /* set feature */
        res = usb_control_msg( udev, usb_sndctrlpipe(udev, 0),
                               USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
                               0xc04e, 0x0000, NULL, 0, HZ * 3 );

        dprintk("%s - res = %d", __func__, res);

        /* These two are sent by the windows driver, but stall for
         * me. I dont have an analyzer on the linux side so i can't
         * see what is actually different and why the device takes
         * issue with them
         */
#if 0
        /* this is some custom control message they send */
        res = usb_control_msg( udev, usb_sndctrlpipe(udev, 0),
                               0x04, USB_TYPE_VENDOR,
                               0x0808, 0x0000, NULL, 0, HZ * 3 );

        dprintk("%s - res = %d", __func__, res);

        /* this is another custom control message they send */
        res = usb_control_msg( udev, usb_sndctrlpipe(udev, 0),
                               0x02, USB_TYPE_VENDOR,
                               0x0000, 0x0100, NULL, 0, HZ * 3 );

        dprintk("%s - res = %d", __func__, res);
#endif
}

/* Setup routine for newer Phillips remote */
static void mceusb_setup2( struct usb_device *udev, struct usb_skel* dev )
{
        char data[16];
        int res, size;
        
        memset( data, 0, 16 );
        res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                                        USB_REQ_GET_STATUS, USB_DIR_IN, 0, 0,
                                        data, 2, HZ);
        dprintk("%s - Get Status: res = %d, status = 0x%x 0x%x", __func__, res, 
data[0], data[1]);
        
        memset( data, 0, 16 );
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                                        USB_REQ_SET_CONFIGURATION, 0, 1, 0,
                                        data, 0, HZ);
        dprintk("%s - Set Configuration #1: res = %d", __func__, res);
        
        /* Doesn't seem strictly necessary, but the Windows driver does it */
        
        memset( data, 0, 16 );
        data[0] = 0;
        data[1] = 0xFF;
        data[2] = 0xAA;
        data[3] = 0xFF;
        data[4] = 0x0B;
                
        res = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 
dev->bulk_out_endpointAddr),
                data, 5, &size, HZ);
        dprintk("%s - Send #1: res = %d, data = 0x%x 0x%x, size=%d, 
sendAddr=%d", __func__, res, data[0],
data[1], size, dev->bulk_out_endpointAddr);
        if (res == -ETIMEDOUT)
        {
                err("%s - Unsuccessful initialization", __func__);
                return;
        }
        
        memset( data, 0, 16 );
        res = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 
dev->bulk_in_endpointAddr),
                data, 16, &size, HZ);
        dprintk("%s - Receive #1: res = %d, size=%d, receiveAddr=%d", __func__, 
res, size, dev->bulk_in_endpointAddr);
        
        memset( data, 0, 16 );
        data[0] = 0xFF;
        data[1] = 0x18;
        
        res = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 
dev->bulk_out_endpointAddr),
                data, 2, &size, HZ);
        dprintk("%s - Send #2: res = %d, size=%d, sendAddr=%d", __func__, res, 
size, dev->bulk_out_endpointAddr);
        
        memset( data, 0, 16 );
        res = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 
dev->bulk_in_endpointAddr),
                data, 16, &size, HZ * 5);
        dprintk("%s - Receive #2: res = %d, size=%d, receiveAddr=%d", __func__, 
res, size, dev->bulk_in_endpointAddr);
}

static void msir_cleanup( struct usb_skel* dev )
{
        memset( dev->bulk_in_buffer, 0, dev->bulk_in_size );

        dev->usb_valid_bytes_in_bulk_buffer = 0;

        dev->last_space = PULSE_MASK;

        dev->mce_bytes_left_in_packet = 0;
        dev->lircidx = 0;
        dev->lirccnt = 0;
        memset( dev->lircdata, 0, sizeof(dev->lircdata) );
}

static int set_use_inc(void* data)
{
        MOD_INC_USE_COUNT;
        return 0;
}

static void set_use_dec(void* data)
{
        /* check for unplug here */
        struct usb_skel* dev = (struct usb_skel*) data;
        if( !dev->udev )
        { 
                lirc_unregister_plugin( dev->minor );
                lirc_buffer_free( dev->plugin->rbuf );
                kfree( dev->plugin->rbuf );
                kfree( dev->plugin );
        }
        
        MOD_DEC_USE_COUNT;
}

/*
 * msir_fetch_more_data
 *
 * The goal here is to read in more remote codes from the remote. In
 * the event that the remote isn't sending us anything, the caller
 * will block until a key is pressed (i.e. this performs phys read,
 * filtering, and queueing of data) unless dont_block is set to 1; in
 * this situation, it will perform a few reads and will exit out if it
 * does not see any appropriate data
 *
 * dev->sem should be locked when this function is called - fine grain
 * locking isn't really important here anyways
 *
 * This routine always returns the number of words available
 *
 */
static int msir_fetch_more_data( struct usb_skel* dev, int dont_block )
{
        int retries = 0;
        int words_to_read = 
                (sizeof(dev->lircdata)/sizeof(lirc_t)) - dev->lirccnt;
        int partial, this_read = 0;
        int bulkidx = 0;
        int bytes_left_in_packet = 0;
        signed char* signedp = (signed char*)dev->bulk_in_buffer;
        
        if( words_to_read == 0 )
                return dev->lirccnt;

        /* this forces all existing data to be read by lirc before we
         * issue another usb command. this is the only form of
         * throttling we have
         */
        if( dev->lirccnt )
        {
                return dev->lirccnt;
        }

        /* reserve room for our leading space */
        if( dev->last_space )
                words_to_read--;
                
        while( words_to_read )
        {
                /* handle signals and USB disconnects */
                if( signal_pending(current) )
                {
                        return dev->lirccnt ? dev->lirccnt : -EINTR;
                }
                if( !dev->udev )
                {
                        return -ENODEV;
                }

                bulkidx = 0;

                /*
                 * perform data read (phys or from previous buffer)
                 */

                /* use leftovers if present, otherwise perform a read */
                if( dev->usb_valid_bytes_in_bulk_buffer )
                {
                        this_read = partial = 
                                dev->usb_valid_bytes_in_bulk_buffer;
                        dev->usb_valid_bytes_in_bulk_buffer = 0;
                }
                else
                {
                        int retval;

                        this_read = dev->bulk_in_size;
                        partial = 0;
                        retval = usb_bulk_msg
                                (dev->udev,
                                 usb_rcvbulkpipe
                                 (dev->udev, dev->bulk_in_endpointAddr),
                                 (unsigned char*)dev->bulk_in_buffer,
                                 this_read, &partial, HZ/4);
                                 
                        /* retry a few times on overruns; map all
                           other errors to -EIO */
                        if( retval )
                        {
                                if( retval == -EOVERFLOW && 
                                    retries < 5 )
                                {
                                        retries++;
                                        interruptible_sleep_on_timeout
                                                ( &dev->wait_q, HZ );
                                        continue;
                                }
                                else
                                {
                                        return -EIO;
                                }
                        }

                        retries = 0;
                        if( partial )
                                this_read = partial;

                        /* skip the header */
                        bulkidx += dev->header_bytes;

                        /* check for empty reads (header only) */
                        if (dev->header_bytes > 0 && this_read == 
dev->header_bytes)
                        {
                                /* assume no data */
                                if( dont_block )
                                {
                                        break;
                                }

                                /* sleep for a bit before performing
                                   another read */
                                interruptible_sleep_on_timeout
                                        ( &dev->wait_q, 1 );
                                continue;
                        }
                }

                /*
                 * process data
                 */

                /* at this point this_read is > 0 */
                while( bulkidx < this_read &&
                       (words_to_read > (dev->last_space ? 1 : 0)) )
                        //while( bulkidx < this_read && words_to_read )
                {
                        int keycode;
                        int pulse = 0;

                        /* read packet length if needed */
                        if( !bytes_left_in_packet )
                        {
                                
                                /* we assume we are on a packet length
                                 * value. it is possible, in some
                                 * cases, to get a packet that does
                                 * not start with a length, apparently
                                 * due to some sort of fragmenting,
                                 * but occaisonally we do not receive
                                 * the second half of a fragment
                                 */
                                bytes_left_in_packet = 
                                        128 + signedp[bulkidx++];
                                        
                                                                        
                                /* This is a bit of a hack. Basically,
                                   timing out the bulk transfer on the
                                   new remote delays key presses noticeably,
                                   so this tries to quit early when it
                                   reaches the end of transmission - Jim */
                                if (bytes_left_in_packet == 31 && 
dev->remote_type == 2)
                                {
                                        dev->mce_bytes_left_in_packet = 0;
                                        return dev->lirccnt;
                                }

                                /* unfortunately rather than keep all
                                 * the data in the packetized format,
                                 * the transceiver sends a trailing 8
                                 * bytes that aren't part of the
                                 * transmittion from the remote,
                                 * aren't packetized, and dont really
                                 * have any value. we can basically
                                 * tell we have hit them if 1) we have
                                 * a loooong space currently stored
                                 * up, and 2) the bytes_left value for
                                 * this packet is obviously wrong
                                 */
                                if( bytes_left_in_packet > 4  )
                                {
                                        if( dev->mce_bytes_left_in_packet )
                                        {
                                                bytes_left_in_packet = 
dev->mce_bytes_left_in_packet;
                                                bulkidx--;
                                        }
                                        bytes_left_in_packet = 0;
                                        bulkidx = this_read;
                                }

                                /* always clear this if we have a
                                   valid packet */
                                dev->mce_bytes_left_in_packet = 0;

                                /* continue here to verify we haven't
                                   hit the end of the bulk_in */
                                continue;
                                
                        }

                        /*
                         * generate mode2
                         */

                        keycode = signedp[bulkidx++];
                        if( keycode < 0 )
                        {
                                pulse = 1;
                                keycode += 128;
                        }
                        keycode *= MCE_TIME_UNIT;

                        bytes_left_in_packet--;

                        if( pulse )
                        {
                                if( dev->last_space )
                                {
                                        dev->lircdata[dev->lirccnt++] =
                                                dev->last_space;
                                        dev->last_space = 0;
                                        words_to_read--;

                                        /* clear the lirc_t for the pulse */
                                        dev->lircdata[dev->lirccnt] = 0;
                                }
                                dev->lircdata[dev->lirccnt] += keycode;
                                dev->lircdata[dev->lirccnt] |= PULSE_BIT;
                        }
                        else
                        {
                                /* on pulse->space transition, add one
                                   for the existing pulse */
                                if( dev->lircdata[dev->lirccnt] &&
                                    !dev->last_space )
                                {
                                        dev->lirccnt++;
                                        words_to_read--;
                                }

                                dev->last_space += keycode;
                        }
                }
        }
        
        /* save off some info if we are exiting mid-packet, or with
           leftovers */
        if( bytes_left_in_packet )
        {
                dev->mce_bytes_left_in_packet = bytes_left_in_packet;
        }
        if( bulkidx < this_read )
        {
                dev->usb_valid_bytes_in_bulk_buffer = (this_read - bulkidx);
                memcpy( dev->bulk_in_buffer, &(dev->bulk_in_buffer[bulkidx]),
                        dev->usb_valid_bytes_in_bulk_buffer );
        }
        return dev->lirccnt;
}

/* mceusb_add_to_buf: called by lirc_dev to fetch all available keys
 * this is used as a polling interface for us: since we set
 * plugin->sample_rate we will periodically get the below call to
 * check for new data returns 0 on success, or -ENODATA if nothing is
 * available
 */
static int mceusb_add_to_buf(void* data, struct lirc_buffer* buf )
{
        struct usb_skel* dev = (struct usb_skel*) data;

        down( &dev->sem );

        /* verify device still present */
        if( dev->udev == NULL )
        {
                up( &dev->sem );
                return -ENODEV;
        }

        if( !dev->lirccnt )
        {
                int res;
                dev->lircidx = 0;

                res = msir_fetch_more_data( dev, 1 );
                
                if( res == 0 )
                        res = -ENODATA;
                if( res < 0 ) {
                        up( &dev->sem );
                        return res;
                }
        }

        if( dev->lirccnt )
        {
                int keys_to_copy;

                /* determine available buffer space and available data */
                keys_to_copy = lirc_buffer_available( buf );
                if( keys_to_copy > dev->lirccnt )
                {
                        keys_to_copy = dev->lirccnt;
                }

                lirc_buffer_write_n( buf, (unsigned char*) 
&(dev->lircdata[dev->lircidx]), keys_to_copy );
                dev->lircidx += keys_to_copy;
                dev->lirccnt -= keys_to_copy;

                up( &dev->sem );
                return 0;
        }

        up( &dev->sem );
        return -ENODATA;
}

/**
 *      mceusb_write_bulk_callback
 */
#ifdef KERNEL_2_5 
static void mceusb_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
#else
static void mceusb_write_bulk_callback (struct urb *urb)
#endif
{
        struct usb_skel *dev = (struct usb_skel *)urb->context;

        dprintk("%s - minor %d", __func__, dev->minor);

        if ((urb->status != -ENOENT) && 
            (urb->status != -ECONNRESET)) {
                dprintk("%s - nonzero write buld status received: %d",
                        __func__, urb->status);
                return;
        }

        return;
}

/**
 *      mceusb_probe
 *
 *      Called by the usb core when a new device is connected that it 
 *      thinks this driver might be interested in.
 */
#ifdef KERNEL_2_5 
static int mceusb_probe(struct usb_interface *interface, const struct 
usb_device_id *id)
{
        struct usb_device *udev = interface_to_usbdev(interface);
        struct usb_host_interface *iface_desc;
#else
static void * mceusb_probe(struct usb_device *udev, unsigned int ifnum,
                           const struct usb_device_id *id)
{
        struct usb_interface *interface = &udev->actconfig->interface[ifnum];
        struct usb_interface_descriptor *iface_desc;    
#endif
        struct usb_skel *dev = NULL;
        struct usb_endpoint_descriptor *endpoint;
        
        struct lirc_plugin* plugin;
        struct lirc_buffer* rbuf;

        int minor;
        size_t buffer_size;
        int i, remote_type;
        int retval = -ENOMEM;
        
        /* See if the device offered us matches what we can accept */
        if (udev->descriptor.idVendor == USB_MCEUSB_VENDOR_ID1 &&
                udev->descriptor.idProduct == USB_MCEUSB_PRODUCT_ID1) {
                remote_type = 1;
        }
        else if (udev->descriptor.idVendor == USB_MCEUSB_VENDOR_ID2 &&
                        udev->descriptor.idProduct == USB_MCEUSB_PRODUCT_ID2) {
                remote_type = 2;
        }
        else
        {
                dprintk("Wrong Vendor/Product IDs");
                
#ifdef KERNEL_2_5
                return -ENODEV;
#else
                return NULL;
#endif
        }

        /* select a "subminor" number (part of a minor number) */
        down (&minor_table_mutex);
        for (minor = 0; minor < MAX_DEVICES; ++minor) {
                if (minor_table[minor] == NULL)
                        break;
        }
        if (minor >= MAX_DEVICES) {
                info ("Too many devices plugged in, "
                      "can not handle this device.");
                goto error;
        }

        /* allocate memory for our device state and initialize it */
        dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL);
        if (dev == NULL) {
                err ("Out of memory");
#ifdef KERNEL_2_5
                retval = -ENOMEM;
#endif
                goto error;
        }
        minor_table[minor] = dev;
        
        memset (dev, 0x00, sizeof (*dev));
        init_MUTEX (&dev->sem);
        dev->udev = udev;
        dev->interface = interface;
        dev->minor = minor;

        /* set up the endpoint information */
        /* check out the endpoints */
        /* use only the first bulk-in and bulk-out endpoints */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,4)
        iface_desc = interface->cur_altsetting;
#else
        iface_desc = &interface->altsetting[0];
#endif

#ifdef KERNEL_2_5
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
#else
        for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i];
#endif
                if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) &&
                    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
                     USB_ENDPOINT_XFER_BULK)) {
                        dprintk("we found a bulk in endpoint");
                        buffer_size = endpoint->wMaxPacketSize;
                        dev->bulk_in_size = buffer_size;
                        dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
#ifdef KERNEL_2_5
                        dev->bulk_in_buffer = usb_buffer_alloc
                                (udev, buffer_size, SLAB_ATOMIC, &dev->dma_in);
#else
                        dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
#endif
                        if (!dev->bulk_in_buffer) {
                                err("Couldn't allocate bulk_in_buffer");
                                goto error;
                        }
                }
                
                if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == 
0x00) &&
                    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
                     USB_ENDPOINT_XFER_BULK)) {
                        dprintk("we found a bulk out endpoint");
#ifdef KERNEL_2_5
                        dev->write_urb = usb_alloc_urb(0, GFP_KERNEL);
#else
                        dev->write_urb = usb_alloc_urb(0);
#endif
                        if (!dev->write_urb) {
                                err("No free urbs available");
                                goto error;
                        }
                        buffer_size = endpoint->wMaxPacketSize;
                        dev->bulk_out_size = buffer_size;
                        dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
#ifdef KERNEL_2_5
                        dev->bulk_out_buffer = usb_buffer_alloc(udev, 
buffer_size, SLAB_ATOMIC, &dev->dma_out);
#else
                        dev->bulk_out_buffer = kmalloc (buffer_size, 
GFP_KERNEL);
#endif
                        if (!dev->bulk_out_buffer) {
                                err("Couldn't allocate bulk_out_buffer");
                                goto error;
                        }
#ifdef KERNEL_2_5
                        usb_fill_bulk_urb(dev->write_urb, udev, 
                                      usb_sndbulkpipe
                                      (udev, endpoint->bEndpointAddress),
                                      dev->bulk_out_buffer, buffer_size,
                                      mceusb_write_bulk_callback, dev);
#else
                        FILL_BULK_URB(dev->write_urb, udev,
                                      usb_sndbulkpipe
                                      (udev, endpoint->bEndpointAddress),
                                      dev->bulk_out_buffer, buffer_size,
                                      mceusb_write_bulk_callback, dev);
#endif
                }
        }

        if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
                err("Couldn't find both bulk-in and bulk-out endpoints");
                goto error;
        }

        /* init the waitq */
        init_waitqueue_head( &dev->wait_q );

        /* Set up our lirc plugin */
        if(!(plugin = kmalloc(sizeof(struct lirc_plugin), GFP_KERNEL))) {
                err("out of memory");
                goto error;
        }
        memset( plugin, 0, sizeof(struct lirc_plugin) );

        if(!(rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL))) {
                err("out of memory");
                kfree( plugin );
                goto error;
        }

        /* the lirc_atiusb module doesn't memset rbuf here ... ? */
        if( lirc_buffer_init( rbuf, sizeof(lirc_t), 128)) {
                err("out of memory");
                kfree( plugin );
                kfree( rbuf );
                goto error;
        }

        strcpy(plugin->name, DRIVER_NAME " ");
        plugin->minor       = minor;
        plugin->code_length = sizeof(lirc_t) * 8;
        plugin->features    = LIRC_CAN_REC_MODE2; // | LIRC_CAN_SEND_MODE2;
        plugin->data        = dev;
        plugin->rbuf        = rbuf;
        plugin->ioctl       = NULL;
        plugin->set_use_inc = &set_use_inc;
        plugin->set_use_dec = &set_use_dec;
        plugin->sample_rate = 80;   // sample at 100hz (10ms)
        plugin->add_to_buf  = &mceusb_add_to_buf;
        //    plugin->fops        = &mceusb_fops;
        if( lirc_register_plugin(plugin) < 0 )
        {
                kfree( plugin );
                lirc_buffer_free( rbuf );
                kfree( rbuf );
                goto error;
        }
        dev->plugin = plugin;
        
        /* clear off the first few messages. these look like
         * calibration or test data, i can't really tell
         * this also flushes in case we have random ir data queued up
         */
        {
                char junk[64];
                int partial = 0, retval;
                do
                {
                        retval = usb_bulk_msg
                                        (udev, usb_rcvbulkpipe
                                         (udev, dev->bulk_in_endpointAddr),
                                         junk, 64,
                                         &partial, HZ);
                } while (partial > 0);
        }

        msir_cleanup( dev );
        
        dev->remote_type = remote_type;
        if (remote_type == 1)
        {
                dev->header_bytes = 2;
                mceusb_setup1( udev );
        }
        else
        {
                dev->header_bytes = 0;
                mceusb_setup2( udev, dev );
        }
        
#ifdef KERNEL_2_5
        /* we can register the device now, as it is ready */
        usb_set_intfdata (interface, dev);
#endif  
        /* let the user know what node this device is now attached to */
        //info ("USB Microsoft IR Transceiver device now attached to msir%d", 
dev->minor);
        up (&minor_table_mutex);
#ifdef KERNEL_2_5
        return 0;
#else
        return dev;
#endif
 error:
        mceusb_delete (dev);
        dev = NULL;
        dprintk("%s: retval = %x", __func__, retval);
        up (&minor_table_mutex);
#ifdef KERNEL_2_5
        return retval;
#else
        return NULL;
#endif
}

/**
 *      mceusb_disconnect
 *
 *      Called by the usb core when the device is removed from the system.
 *
 *      This routine guarantees that the driver will not submit any more urbs
 *      by clearing dev->udev.  It is also supposed to terminate any currently
 *      active urbs.  Unfortunately, usb_bulk_msg(), used in skel_read(), does
 *      not provide any way to do this.  But at least we can cancel an active
 *      write.
 */
#ifdef KERNEL_2_5 
static void mceusb_disconnect(struct usb_interface *interface)
#else
static void mceusb_disconnect(struct usb_device *udev, void *ptr)
#endif
{
        struct usb_skel *dev;
        int minor;
#ifdef KERNEL_2_5
        dev = usb_get_intfdata (interface);
        usb_set_intfdata (interface, NULL);
#else
        dev = (struct usb_skel *)ptr;
#endif
        
        down (&minor_table_mutex);
        down (&dev->sem);
        minor = dev->minor;

        /* unhook lirc things */
        lirc_unregister_plugin( minor );
        lirc_buffer_free( dev->plugin->rbuf );
        kfree( dev->plugin->rbuf );
        kfree( dev->plugin );
#ifdef KERNEL_2_5
        /* terminate an ongoing write */
        if (atomic_read (&dev->write_busy)) {
                usb_unlink_urb (dev->write_urb);
                wait_for_completion (&dev->write_finished);
        }

        /* prevent device read, write and ioctl */
        dev->present = 0;
#endif
        
        mceusb_delete (dev);
        
        info("Microsoft IR Transceiver #%d now disconnected", minor);
        up (&dev->sem);
        up (&minor_table_mutex);
}

/**
 *      usb_mceusb_init
 */
static int __init usb_mceusb_init(void)
{
        int result;

        /* register this driver with the USB subsystem */
        result = usb_register(&mceusb_driver);
#ifdef KERNEL_2_5       
        if ( result ) {
#else
        if ( result < 0 ) {
#endif
                err("usb_register failed for the " DRIVER_NAME " driver. error 
number %d",result);
#ifdef KERNEL_2_5
                return result;
#else
                return -1;
#endif
        }

        info(DRIVER_DESC " " DRIVER_VERSION);
        return 0;
}

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

 module_init (usb_mceusb_init);
module_exit (usb_mceusb_exit);

MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE (usb, mceusb_table);

module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug enabled or not");

EXPORT_NO_SYMBOLS;
_______________________________________________
mythtv-users mailing list
[email protected]
http://mythtv.org/cgi-bin/mailman/listinfo/mythtv-users

Reply via email to