add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,229 @@
# LIRC http://lirc.sf.net/
# Kernel patch by Flameeyes <dgp85@users.sf.net>
# Check for new patch at http://flameeyes.web.ctonet.it
#
# Thanks to Koos Vriezen <koos.vriezen@xs4all.nl> for the Homebrew support.
# Thanks to Jeff Clark <jeff@tmtrading.com> for support when I wasn't able
# to update it and for his patch (found at http://www.clarkmania.com/~jclark/
# Thanks to Bernhard Rosenkraenzer <bero@arklinux.org> for SMP patch.
# Thanks to Vince <fuzzy77@free.fr> for the temporary lirc_atiusb driver.
# Thanks to Paul Miller <pmiller9@users.sourceforge.net> for the new working
# lirc_atiusb driver.
menu "Linux InfraRed Controller"
config LIRC_SUPPORT
tristate "Linux InfraRed Controller"
config LIRC_MCEUSB
tristate "MCE USB Driver"
depends on LIRC_SUPPORT && USB
help
USB Microsoft IR Transceiver driver
config LIRC_MCEUSB2
tristate "MCE USB Driver"
depends on LIRC_SUPPORT && USB
help
LIRC driver for the Philips eHome USB Infrared
Transciever and the Microsoft MCE 2005 Remote Control
config LIRC_SERIAL
tristate "Serial Driver"
depends on LIRC_SUPPORT && SERIAL_8250
choice
prompt "Serial Receiver Type"
depends on LIRC_SERIAL
config LIRC_HOMEBREW
bool "Homebrew"
config LIRC_SERIAL_ANIMAX
bool "Animax"
config LIRC_SERIAL_IRDEO
bool "IRdeo"
config LIRC_SERIAL_IRDEO_REMOTE
bool "IRdeo Remote"
config LIRC_SERIAL_NSLU2
bool "NSLU2"
config LIRC_SERIAL_IGOR
bool "Igor Ceska's variation"
endchoice
config LIRC_SERIAL_TRANSMITTER
bool "With transmitter diode"
depends on LIRC_SERIAL && !LIRC_SERIAL_ANIMAX
config LIRC_SERIAL_SOFTCARRIER
bool "With software carrier"
depends on LIRC_SERIAL_TRANSMITTER
choice
prompt "Serial Port"
depends on LIRC_SERIAL
config LIRC_SERIAL_COM1
bool "COM1 (0x3f8, 4)"
config LIRC_SERIAL_COM2
bool "COM2 (0x2f8, 3)"
config LIRC_SERIAL_COM3
bool "COM3 (0x3e8, 4)"
config LIRC_SERIAL_COM4
bool "COM4 (0x2e8, 3)"
config LIRC_SERIAL_OTHER
bool "Other (custom values)"
endchoice
config LIRC_PORT_SERIAL
hex "I/O Port"
default "0x3f8" if LIRC_SERIAL_COM1
default "0x2f8" if LIRC_SERIAL_COM2
default "0x3e8" if LIRC_SERIAL_COM3
default "0x2e8" if LIRC_SERIAL_COM4
depends on LIRC_SERIAL
config LIRC_IRQ_SERIAL
hex "IRQ"
default "4" if LIRC_SERIAL_COM1 || LIRC_SERIAL_COM3
default "3" if LIRC_SERIAL_COM2 || LIRC_SERIAL_COM4
depends on LIRC_SERIAL
config LIRC_SIR
tristate "SIR Driver"
depends on LIRC_SUPPORT
config LIRC_ON_SA1100
bool "LIRC driver for StrongARM SA1100 embedded microprocessor"
depends on LIRC_SIR
choice
prompt "SIR Type"
depends on LIRC_SIR && !LIRC_ON_SA1100
config LIRC_SIR_IRDA
bool "SIR IrDA (built-in IR ports)"
config LIRC_SIR_TEKRAM
bool "Tekram Irmate 210 (16x50 UART compatible serial port)"
config LIRC_SIR_ACTISYS_ACT200L
bool "Actisys Act200L SIR driver support"
endchoice
choice
prompt "Serial Port"
depends on LIRC_SIR
config LIRC_SIR_COM1
bool "COM1 (0x3f8, 4)"
config LIRC_SIR_COM2
bool "COM2 (0x2f8, 3)"
config LIRC_SIR_COM3
bool "COM3 (0x3e8, 4)"
config LIRC_SIR_COM4
bool "COM4 (0x2e8, 3)"
config LIRC_SIR_OTHER
bool "Other (custom values)"
endchoice
config LIRC_PORT_SIR
hex "I/O Port"
default "0x3f8" if LIRC_SIR_COM1
default "0x2f8" if LIRC_SIR_COM2
default "0x3e8" if LIRC_SIR_COM3
default "0x2e8" if LIRC_SIR_COM4
depends on LIRC_SIR
config LIRC_IRQ_SIR
hex "IRQ"
default "4" if LIRC_SIR_COM1 || LIRC_SIR_COM3
default "3" if LIRC_SIR_COM2 || LIRC_SIR_COM4
depends on LIRC_SIR
config LIRC_STM
tristate "STM Driver"
depends on LIRC_SUPPORT && CPU_SUBTYPE_ST40
help
The IR and UHF RX processors are identical and independent,
except that the IR receiver does not use the noise and
SCD filters. Not all ST platforms support both type of
receivers.
IR RX receiver is the default mode.
config LIRC_STM_UHF
bool "UHF RX receiver processor"
depends on LIRC_STM
help
Set this option to enable UHF instead of IR remote control input.
Note this option has no direct effect in the LiRC driver. It is used by
some boards which have support for both UHF and IR support to set the
configuration parameters passed into the driver. Not all boards have
support for both modes of operation, so this option may have no effect,
and hardware changes (such as changing jumpers) may be required.
config LIRC_STM_UHF_SCD
bool "Start Code Detector - SCD"
depends on LIRC_STM_UHF
default n
help
This causes the driver to use SCD on UHF RX mode.
The start code detector detects any programmable start
code on UHF RX input. It works on a time unit called
symbol time. One graphical example to understand how to
configure properly the code, code length and nominal time
values based on Remote Control signals train can be found in
drivers/char/lirc/lirc_stm.c driver.
config LIRC_STM_UHF_SCD_CODE
hex "Normal code to be detected"
default "0x3FFFC028"
depends on LIRC_STM_UHF_SCD
help
The primary RC to be detected.
Default value for Futarque RC is 0x3FFFC028.
config LIRC_STM_UHF_SCD_ALTCODE
hex "Alternative code to be detected"
default "0x0"
depends on LIRC_STM_UHF_SCD
help
The second RC to be detected as alternative of the primary.
The primary must be always setup before the use this.
config LIRC_STM_UHF_SCD_NTIME
hex "Nominal time for a symbol"
default "0x1f4"
depends on LIRC_STM_UHF_SCD
help
Default value for Futarque RC is 0x1f4. The nominal time
is the same for normal and alternative symbols calculation.
config LIRC_STM_TX
depends on LIRC_STM
bool "IRB TX transmitter processor"
default n
help
Say yes if you want enable IR transmission. The IR TX processor is
independent of IR RX mode.
config LIRC_STM_DEBUG
depends on LIRC_STM
bool "Driver debug"
default n
help
Say yes if you want enable some debug printk information
config LIRC_TTUSBIR
tristate "Technotrend USB IR Receiver"
depends on LIRC_SUPPORT && USB
help
Driver for the Technotrend USB IR Receiver
endmenu

View File

@@ -0,0 +1,13 @@
#
# Makefile for LIRC drivers
#
# Copyright (C) 2004-2009 STMicroelectronics
# Author Angelo Castello <angelo.castello@st.com>
obj-$(CONFIG_LIRC_SUPPORT) += lirc_dev.o
obj-$(CONFIG_LIRC_MCEUSB2) += lirc_mceusb2.o
obj-$(CONFIG_LIRC_MCEUSB) += lirc_mceusb.o
obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o
obj-$(CONFIG_LIRC_SIR) += lirc_sir.o
obj-$(CONFIG_LIRC_STM) += lirc_stm.o
obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o

View File

@@ -0,0 +1,402 @@
/* $Id: kcompat.h,v 5.44 2009/03/22 08:45:47 lirc Exp $ */
#ifndef _KCOMPAT_H
#define _KCOMPAT_H
#include <linux/version.h>
#ifndef __func__
#define __func__ __FUNCTION__
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
#define LIRC_THIS_MODULE(x) x,
#else /* >= 2.6.16 */
#define LIRC_THIS_MODULE(x)
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
#include <linux/device.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
#define LIRC_HAVE_DEVFS
#define LIRC_HAVE_DEVFS_26
#endif
#define LIRC_HAVE_SYSFS
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
typedef struct class_simple lirc_class_t;
static inline lirc_class_t *class_create(struct module *owner, char *name)
{
return class_simple_create(owner, name);
}
static inline void class_destroy(lirc_class_t *cls)
{
class_simple_destroy(cls);
}
#define lirc_device_create(cs, parent, dev, drvdata, fmt, args...) \
class_simple_device_add(cs, dev, parent, fmt, ## args)
static inline void lirc_device_destroy(lirc_class_t *cls, dev_t devt)
{
class_simple_device_remove(devt);
}
#else /* >= 2.6.13 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
#define lirc_device_create(cs, parent, dev, drvdata, fmt, args...) \
class_device_create(cs, dev, parent, fmt, ## args)
#else /* >= 2.6.15 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
#define lirc_device_create(cs, parent, dev, drvdata, fmt, args...) \
class_device_create(cs, NULL, dev, parent, fmt, ## args)
#else /* >= 2.6.26 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
#define lirc_device_create(cs, parent, dev, drvdata, fmt, args...) \
device_create(cs, parent, dev, fmt, ## args)
#else /* >= 2.6.27 */
#define lirc_device_create device_create
#endif /* >= 2.6.27 */
#endif /* >= 2.6.26 */
#define LIRC_DEVFS_PREFIX
#endif /* >= 2.6.15 */
typedef struct class lirc_class_t;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
#define lirc_device_destroy class_device_destroy
#else
#define lirc_device_destroy device_destroy
#endif
#endif /* >= 2.6.13 */
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
#define LIRC_HAVE_DEVFS
#define LIRC_HAVE_DEVFS_24
#endif
#ifndef LIRC_DEVFS_PREFIX
#define LIRC_DEVFS_PREFIX "usb/"
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
#include <linux/timer.h>
#include <linux/interrupt.h>
static inline void del_timer_sync(struct timer_list *timerlist)
{
start_bh_atomic();
del_timer(timerlist);
end_bh_atomic();
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
#ifdef daemonize
#undef daemonize
#endif
#define daemonize(name) do { \
\
lock_kernel(); \
\
exit_mm(current); \
exit_files(current); \
exit_fs(current); \
current->session = 1; \
current->pgrp = 1; \
current->euid = 0; \
current->tty = NULL; \
sigfillset(&current->blocked); \
\
strcpy(current->comm, name); \
\
unlock_kernel(); \
\
} while (0)
/* Not sure when this was introduced, sometime during 2.5.X */
#define MODULE_PARM_int(x) MODULE_PARM(x, "i")
#define MODULE_PARM_bool(x) MODULE_PARM(x, "i")
#define MODULE_PARM_long(x) MODULE_PARM(x, "l")
#define module_param(x, y, z) MODULE_PARM_##y(x)
#else
#include <linux/moduleparam.h>
#endif /* Linux < 2.6.0 */
/* DevFS header */
#if defined(LIRC_HAVE_DEVFS)
#include <linux/devfs_fs_kernel.h>
#endif
#ifdef LIRC_HAVE_DEVFS_24
#ifdef register_chrdev
#undef register_chrdev
#endif
#define register_chrdev devfs_register_chrdev
#ifdef unregister_chrdev
#undef unregister_chrdev
#endif
#define unregister_chrdev devfs_unregister_chrdev
#endif /* DEVFS 2.4 */
#ifndef LIRC_HAVE_SYSFS
#define class_destroy(x) do { } while (0)
#define class_create(x, y) NULL
#define lirc_device_destroy(x, y) do { } while (0)
#define lirc_device_create(x, y, z, xx, yy, zz) 0
#define IS_ERR(x) 0
typedef struct class_simple
{
int notused;
} lirc_class_t;
#endif /* No SYSFS */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
#define KERNEL_2_5
/*
* We still are using MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT in the set_use_inc
* function of all modules for 2.4 kernel compatibility.
*
* For 2.6 kernels reference counting is done in lirc_dev by
* try_module_get()/module_put() because the old approach is racy.
*
*/
#ifdef MOD_INC_USE_COUNT
#undef MOD_INC_USE_COUNT
#endif
#define MOD_INC_USE_COUNT
#ifdef MOD_DEC_USE_COUNT
#undef MOD_DEC_USE_COUNT
#endif
#define MOD_DEC_USE_COUNT
#ifdef EXPORT_NO_SYMBOLS
#undef EXPORT_NO_SYMBOLS
#endif
#define EXPORT_NO_SYMBOLS
#else /* Kernel < 2.5.0 */
static inline int try_module_get(struct module *module)
{
return 1;
}
static inline void module_put(struct module *module)
{
}
#endif /* Kernel >= 2.5.0 */
#ifndef MODULE_LICENSE
#define MODULE_LICENSE(x)
#endif
#ifndef MODULE_PARM_DESC
#define MODULE_PARM_DESC(x, y)
#endif
#ifndef MODULE_ALIAS_CHARDEV_MAJOR
#define MODULE_ALIAS_CHARDEV_MAJOR(x)
#endif
#ifndef MODULE_DEVICE_TABLE
#define MODULE_DEVICE_TABLE(x, y)
#endif
#include <linux/interrupt.h>
#ifndef IRQ_RETVAL
typedef void irqreturn_t;
#define IRQ_NONE
#define IRQ_HANDLED
#define IRQ_RETVAL(x)
#endif
#ifndef MOD_IN_USE
#ifdef CONFIG_MODULE_UNLOAD
#define MOD_IN_USE module_refcount(THIS_MODULE)
#else
#error "LIRC modules currently require"
#error " 'Loadable module support ---> Module unloading'"
#error "to be enabled in the kernel"
#endif
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
#if !defined(local_irq_save)
#define local_irq_save(flags) do { save_flags(flags); cli(); } while (0)
#endif
#if !defined(local_irq_restore)
#define local_irq_restore(flags) do { restore_flags(flags); } while (0)
#endif
#endif
#if KERNEL_VERSION(2, 4, 0) <= LINUX_VERSION_CODE
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 22)
#include <linux/pci.h>
static inline char *pci_name(struct pci_dev *pdev)
{
return pdev->slot_name;
}
#endif /* kernel < 2.4.22 */
#endif /* kernel >= 2.4.0 */
/*************************** I2C specific *****************************/
#include <linux/i2c.h>
#ifndef I2C_CLIENT_END
#error "********************************************************"
#error " Sorry, this driver needs the new I2C stack. "
#error " You can get it at http://www2.lm-sensors.nu/~lm78/. "
#error "********************************************************"
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
#undef i2c_get_clientdata
#define i2c_get_clientdata(client) ((client)->data)
#undef i2c_set_clientdata
#define i2c_set_clientdata(client_ptr, new_data) do { \
(client_ptr)->data = new_data; \
} while (0)
#endif
/* removed in 2.6.14 */
#ifndef I2C_ALGO_BIT
# define I2C_ALGO_BIT 0
#endif
/* removed in 2.6.16 */
#ifndef I2C_DRIVERID_EXP3
# define I2C_DRIVERID_EXP3 0xf003
#endif
/*************************** USB specific *****************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
#include <linux/usb.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
static inline int usb_kill_urb(struct urb *urb)
{
return usb_unlink_urb(urb);
}
#endif
/* removed in 2.6.14 */
#ifndef URB_ASYNC_UNLINK
#define URB_ASYNC_UNLINK 0
#endif
#endif
/*************************** bttv specific ****************************/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) /* BTTV_* -> BTTV_BOARD_* */
#define BTTV_BOARD_UNKNOWN BTTV_UNKNOWN
#define BTTV_BOARD_PXELVWPLTVPAK BTTV_PXELVWPLTVPAK
#define BTTV_BOARD_PXELVWPLTVPRO BTTV_PXELVWPLTVPRO
#define BTTV_BOARD_PV_BT878P_9B BTTV_PV_BT878P_9B
#define BTTV_BOARD_PV_BT878P_PLUS BTTV_PV_BT878P_PLUS
#define BTTV_BOARD_AVERMEDIA BTTV_AVERMEDIA
#define BTTV_BOARD_AVPHONE98 BTTV_AVPHONE98
#define BTTV_BOARD_AVERMEDIA98 BTTV_AVERMEDIA98
#define BTTV_BOARD_CHRONOS_VS2 BTTV_CHRONOS_VS2
#define BTTV_BOARD_MIRO BTTV_MIRO
#define BTTV_BOARD_DYNALINK BTTV_DYNALINK
#define BTTV_BOARD_WINVIEW_601 BTTV_WINVIEW_601
#ifdef BTTV_KWORLD
#define BTTV_BOARD_KWORLD BTTV_KWORLD
#endif
#define BTTV_BOARD_MAGICTVIEW061 BTTV_MAGICTVIEW061
#define BTTV_BOARD_MAGICTVIEW063 BTTV_MAGICTVIEW063
#define BTTV_BOARD_PHOEBE_TVMAS BTTV_PHOEBE_TVMAS
#ifdef BTTV_BESTBUY_EASYTV2
#define BTTV_BOARD_BESTBUY_EASYTV BTTV_BESTBUY_EASYTV
#define BTTV_BOARD_BESTBUY_EASYTV2 BTTV_BESTBUY_EASYTV2
#endif
#define BTTV_BOARD_FLYVIDEO BTTV_FLYVIDEO
#define BTTV_BOARD_FLYVIDEO_98 BTTV_FLYVIDEO_98
#define BTTV_BOARD_TYPHOON_TVIEW BTTV_TYPHOON_TVIEW
#ifdef BTTV_FLYVIDEO_98FM
#define BTTV_BOARD_FLYVIDEO_98FM BTTV_FLYVIDEO_98FM
#endif
#define BTTV_BOARD_WINFAST2000 BTTV_WINFAST2000
#ifdef BTTV_GVBCTV5PCI
#define BTTV_BOARD_GVBCTV5PCI BTTV_GVBCTV5PCI
#endif
#endif /* end BTTV_* -> BTTV_BOARD_* */
/******************************* pm.h *********************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
typedef u32 pm_message_t;
#endif /* kernel < 2.6.11 */
#endif /* kernel >= 2.6.0 */
/*************************** interrupt.h ******************************/
/* added in 2.6.18, old defines removed in 2.6.24 */
#ifndef IRQF_DISABLED
#define IRQF_DISABLED SA_INTERRUPT
#endif
#ifndef IRQF_SHARED
#define IRQF_SHARED SA_SHIRQ
#endif
/*************************** spinlock.h *******************************/
/* added in 2.6.11 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
#endif
/***************************** slab.h *********************************/
/* added in 2.6.14 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
static inline void *kzalloc(size_t size, gfp_t flags)
{
void *ret = kmalloc(size, flags);
if (ret)
memset(ret, 0, size);
return ret;
}
#endif
/****************************** fs.h **********************************/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
static inline unsigned iminor(struct inode *inode)
{
return MINOR(inode->i_rdev);
}
#endif
#endif /* _KCOMPAT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,344 @@
/*
* LIRC base driver
*
* (L) by Artur Lipowski <alipowski@interia.pl>
* This code is licensed under GNU GPL
*
* $Id: lirc_dev.h,v 1.37 2009/03/15 09:34:00 lirc Exp $
*
*/
#ifndef _LINUX_LIRC_DEV_H
#define _LINUX_LIRC_DEV_H
#include <linux/version.h>
#define LIRC_REMOVE_DURING_EXPORT
#ifndef LIRC_REMOVE_DURING_EXPORT
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
/* when was it really introduced? */
#define LIRC_HAVE_KFIFO
#endif
#endif
#define MAX_IRCTL_DEVICES 4
#define BUFLEN 16
#define mod(n, div) ((n) % (div))
#include <linux/slab.h>
#include <linux/fs.h>
#ifdef LIRC_HAVE_KFIFO
#include <linux/kfifo.h>
#endif
struct lirc_buffer {
wait_queue_head_t wait_poll;
spinlock_t lock;
unsigned int chunk_size;
unsigned int size; /* in chunks */
/* Using chunks instead of bytes pretends to simplify boundary checking
* And should allow for some performance fine tunning later */
#ifdef LIRC_HAVE_KFIFO
struct kfifo *fifo;
#else
unsigned int fill; /* in chunks */
int head, tail; /* in chunks */
unsigned char *data;
#endif
};
#ifndef LIRC_HAVE_KFIFO
static inline void lirc_buffer_lock(struct lirc_buffer *buf,
unsigned long *flags)
{
spin_lock_irqsave(&buf->lock, *flags);
}
static inline void lirc_buffer_unlock(struct lirc_buffer *buf,
unsigned long *flags)
{
spin_unlock_irqrestore(&buf->lock, *flags);
}
static inline void _lirc_buffer_clear(struct lirc_buffer *buf)
{
buf->head = 0;
buf->tail = 0;
buf->fill = 0;
}
#endif
static inline void lirc_buffer_clear(struct lirc_buffer *buf)
{
#ifdef LIRC_HAVE_KFIFO
if (buf->fifo)
kfifo_reset(buf->fifo);
#else
unsigned long flags;
lirc_buffer_lock(buf, &flags);
_lirc_buffer_clear(buf);
lirc_buffer_unlock(buf, &flags);
#endif
}
static inline int lirc_buffer_init(struct lirc_buffer *buf,
unsigned int chunk_size,
unsigned int size)
{
init_waitqueue_head(&buf->wait_poll);
spin_lock_init(&buf->lock);
#ifndef LIRC_HAVE_KFIFO
_lirc_buffer_clear(buf);
#endif
buf->chunk_size = chunk_size;
buf->size = size;
#ifdef LIRC_HAVE_KFIFO
buf->fifo = kfifo_alloc(size*chunk_size, GFP_KERNEL, &buf->lock);
if (!buf->fifo)
return -ENOMEM;
#else
buf->data = kmalloc(size*chunk_size, GFP_KERNEL);
if (buf->data == NULL)
return -ENOMEM;
memset(buf->data, 0, size*chunk_size);
#endif
return 0;
}
static inline void lirc_buffer_free(struct lirc_buffer *buf)
{
#ifdef LIRC_HAVE_KFIFO
if (buf->fifo)
kfifo_free(buf->fifo);
#else
kfree(buf->data);
buf->data = NULL;
buf->head = 0;
buf->tail = 0;
buf->fill = 0;
buf->chunk_size = 0;
buf->size = 0;
#endif
}
#ifndef LIRC_HAVE_KFIFO
static inline int _lirc_buffer_full(struct lirc_buffer *buf)
{
return (buf->fill >= buf->size);
}
#endif
static inline int lirc_buffer_full(struct lirc_buffer *buf)
{
#ifdef LIRC_HAVE_KFIFO
return kfifo_len(buf->fifo) == buf->size * buf->chunk_size;
#else
unsigned long flags;
int ret;
lirc_buffer_lock(buf, &flags);
ret = _lirc_buffer_full(buf);
lirc_buffer_unlock(buf, &flags);
return ret;
#endif
}
#ifndef LIRC_HAVE_KFIFO
static inline int _lirc_buffer_empty(struct lirc_buffer *buf)
{
return !(buf->fill);
}
#endif
static inline int lirc_buffer_empty(struct lirc_buffer *buf)
{
#ifdef LIRC_HAVE_KFIFO
return !kfifo_len(buf->fifo);
#else
unsigned long flags;
int ret;
lirc_buffer_lock(buf, &flags);
ret = _lirc_buffer_empty(buf);
lirc_buffer_unlock(buf, &flags);
return ret;
#endif
}
#ifndef LIRC_HAVE_KFIFO
static inline int _lirc_buffer_available(struct lirc_buffer *buf)
{
return (buf->size - buf->fill);
}
#endif
static inline int lirc_buffer_available(struct lirc_buffer *buf)
{
#ifdef LIRC_HAVE_KFIFO
return buf->size - (kfifo_len(buf->fifo) / buf->chunk_size);
#else
unsigned long flags;
int ret;
lirc_buffer_lock(buf, &flags);
ret = _lirc_buffer_available(buf);
lirc_buffer_unlock(buf, &flags);
return ret;
#endif
}
#ifndef LIRC_HAVE_KFIFO
static inline void _lirc_buffer_read_1(struct lirc_buffer *buf,
unsigned char *dest)
{
memcpy(dest, &buf->data[buf->head*buf->chunk_size], buf->chunk_size);
buf->head = mod(buf->head+1, buf->size);
buf->fill -= 1;
}
#endif
static inline void lirc_buffer_read(struct lirc_buffer *buf,
unsigned char *dest)
{
#ifdef LIRC_HAVE_KFIFO
if (kfifo_len(buf->fifo) >= buf->chunk_size)
kfifo_get(buf->fifo, dest, buf->chunk_size);
#else
unsigned long flags;
lirc_buffer_lock(buf, &flags);
_lirc_buffer_read_1(buf, dest);
lirc_buffer_unlock(buf, &flags);
#endif
}
#ifndef LIRC_HAVE_KFIFO
static inline void _lirc_buffer_write_1(struct lirc_buffer *buf,
unsigned char *orig)
{
memcpy(&buf->data[buf->tail*buf->chunk_size], orig, buf->chunk_size);
buf->tail = mod(buf->tail+1, buf->size);
buf->fill++;
}
#endif
static inline void lirc_buffer_write(struct lirc_buffer *buf,
unsigned char *orig)
{
#ifdef LIRC_HAVE_KFIFO
kfifo_put(buf->fifo, orig, buf->chunk_size);
#else
unsigned long flags;
lirc_buffer_lock(buf, &flags);
_lirc_buffer_write_1(buf, orig);
lirc_buffer_unlock(buf, &flags);
#endif
}
#ifndef LIRC_HAVE_KFIFO
static inline void _lirc_buffer_write_n(struct lirc_buffer *buf,
unsigned char *orig, int count)
{
int space1;
if (buf->head > buf->tail)
space1 = buf->head - buf->tail;
else
space1 = buf->size - buf->tail;
if (count > space1) {
memcpy(&buf->data[buf->tail * buf->chunk_size], orig,
space1 * buf->chunk_size);
memcpy(&buf->data[0], orig + (space1 * buf->chunk_size),
(count - space1) * buf->chunk_size);
} else {
memcpy(&buf->data[buf->tail * buf->chunk_size], orig,
count * buf->chunk_size);
}
buf->tail = mod(buf->tail + count, buf->size);
buf->fill += count;
}
#endif
static inline void lirc_buffer_write_n(struct lirc_buffer *buf,
unsigned char *orig, int count)
{
#ifdef LIRC_HAVE_KFIFO
kfifo_put(buf->fifo, orig, count * buf->chunk_size);
#else
unsigned long flags;
lirc_buffer_lock(buf, &flags);
_lirc_buffer_write_n(buf, orig, count);
lirc_buffer_unlock(buf, &flags);
#endif
}
struct lirc_driver {
char name[40];
int minor;
unsigned long code_length;
unsigned int buffer_size; /* in chunks holding one code each */
int sample_rate;
unsigned long features;
void *data;
int (*add_to_buf) (void *data, struct lirc_buffer *buf);
#ifndef LIRC_REMOVE_DURING_EXPORT
wait_queue_head_t* (*get_queue) (void *data);
#endif
struct lirc_buffer *rbuf;
int (*set_use_inc) (void *data);
void (*set_use_dec) (void *data);
struct file_operations *fops;
struct device *dev;
struct module *owner;
};
/* name:
* this string will be used for logs
*
* minor:
* indicates minor device (/dev/lirc) number for registered driver
* if caller fills it with negative value, then the first free minor
* number will be used (if available)
*
* code_length:
* length of the remote control key code expressed in bits
*
* sample_rate:
* sample_rate equal to 0 means that no polling will be performed and
* add_to_buf will be triggered by external events (through task queue
* returned by get_queue)
*
* data:
* it may point to any driver data and this pointer will be passed to
* all callback functions
*
* add_to_buf:
* add_to_buf will be called after specified period of the time or
* triggered by the external event, this behavior depends on value of
* the sample_rate this function will be called in user context. This
* routine should return 0 if data was added to the buffer and
* -ENODATA if none was available. This should add some number of bits
* evenly divisible by code_length to the buffer
*
* get_queue:
* this callback should return a pointer to the task queue which will
* be used for external event waiting
*
* rbuf:
* if not NULL, it will be used as a read buffer, you will have to
* write to the buffer by other means, like irq's (see also
* lirc_serial.c).
*
* set_use_inc:
* set_use_inc will be called after device is opened
*
* set_use_dec:
* set_use_dec will be called after device is closed
*
* fops:
* file_operations for drivers which don't fit the current driver model.
*
* Some ioctl's can be directly handled by lirc_dev if the driver's
* ioctl function is NULL or if it returns -ENOIOCTLCMD (see also
* lirc_serial.c).
*
* owner:
* the module owning this struct
*
*/
/* following functions can be called ONLY from user context
*
* returns negative value on error or minor number
* of the registered device if success
* contents of the structure pointed by d is copied
*/
extern int lirc_register_driver(struct lirc_driver *d);
/* returns negative value on error or 0 if success
*/
extern int lirc_unregister_driver(int minor);
/* Returns the private data stored in the lirc_driver
* associated with the given device file pointer.
*/
void *lirc_get_pdata(struct file *file);
#endif

View File

@@ -0,0 +1,867 @@
/*
* USB Microsoft IR Transceiver driver - 0.2
*
* Copyright (c) 2003-2004 Dan Conti (dconti@acm.wwu.edu)
*
* 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.
*
* TODO
* - Fix up minor number, registration of major/minor with usb subsystem
*
*/
#include <linux/autoconf.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>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
#include <asm/uaccess.h>
#else
#include <linux/uaccess.h>
#endif
#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;
#endif
#include "kcompat.h"
#include <linux/lirc.h>
#include "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, dconti@acm.wwu.edu"
#define DRIVER_DESC "USB Microsoft IR Transceiver Driver"
#define DRIVER_NAME "lirc_mceusb"
/* Define these values to match your device */
#define USB_MCEUSB_VENDOR_ID 0x045e
#define USB_MCEUSB_PRODUCT_ID 0x006d
/* table of devices that work with this driver */
static struct usb_device_id mceusb_table[] = {
/* USB Microsoft IR Transceiver */
{ USB_DEVICE(USB_MCEUSB_VENDOR_ID, USB_MCEUSB_PRODUCT_ID) },
/* 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 mceusb_device {
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 */
char num_bulk_in; /* number of bulk in endpoints */
char num_bulk_out; /* number of bulk out endpoints */
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 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 bulk out endpoint */
wait_queue_head_t wait_q; /* for timeouts */
struct mutex lock; /* locks this structure */
struct lirc_driver *driver;
lirc_t lircdata[256]; /* place to store data until lirc processes it */
int lircidx; /* current index */
int lirccnt; /* remaining values */
int usb_valid_bytes_in_bulk_buffer; /* leftover data from prior read */
int mce_bytes_left_in_packet; /* for packets split across reads */
/* 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);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
static void mceusb_write_bulk_callback(struct urb *urb, struct pt_regs *regs);
#else
static void mceusb_write_bulk_callback(struct urb *urb);
#endif
#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 mceusb_device *dev, int dont_block);
/* helper functions */
static void msir_cleanup(struct mceusb_device *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 mceusb_device *minor_table[MAX_DEVICES];
/* lock to protect the minor_table structure */
static DEFINE_MUTEX(minor_table_mutex);
static void mceusb_setup(struct usb_device *udev);
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver mceusb_driver = {
LIRC_THIS_MODULE(.owner = THIS_MODULE)
.name = DRIVER_NAME,
.probe = mceusb_probe,
.disconnect = mceusb_disconnect,
.id_table = mceusb_table,
};
static void mceusb_delete(struct mceusb_device *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);
}
static void mceusb_setup(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 don't 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
}
static void msir_cleanup(struct mceusb_device *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)
{
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->lock 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 mceusb_device *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;
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 = dev->usb_valid_bytes_in_bulk_buffer;
partial = this_read;
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*10);
/*
* 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 += 2;
/* check for empty reads (header only) */
if (this_read == 2) {
/* 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 occasionally we do not receive
* the second half of a fragment
*/
bytes_left_in_packet =
128 + signedp[bulkidx++];
/*
* unfortunately rather than keep all
* the data in the packetized format,
* the transceiver sends a trailing 8
* bytes that aren't part of the
* transmission from the remote,
* aren't packetized, and don't 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 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're 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
* driver->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 mceusb_device *dev = (struct mceusb_device *) data;
mutex_lock(&dev->lock);
if (!dev->lirccnt) {
int res;
dev->lircidx = 0;
res = msir_fetch_more_data(dev, 1);
if (res == 0)
res = -ENODATA;
if (res < 0) {
mutex_unlock(&dev->lock);
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;
mutex_unlock(&dev->lock);
return 0;
}
mutex_unlock(&dev->lock);
return -ENODATA;
}
#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
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 mceusb_device *dev = (struct mceusb_device *)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 mceusb_device *dev = NULL;
struct usb_endpoint_descriptor *endpoint;
struct lirc_driver *driver;
int minor;
size_t buffer_size;
int i;
int retval = -ENOMEM;
char junk[64];
int partial = 0;
/* See if the device offered us matches what we can accept */
if (cpu_to_le16(udev->descriptor.idVendor) != USB_MCEUSB_VENDOR_ID ||
cpu_to_le16(udev->descriptor.idProduct) != USB_MCEUSB_PRODUCT_ID) {
dprintk("Wrong Vendor/Product IDs");
#ifdef KERNEL_2_5
return -ENODEV;
#else
return NULL;
#endif
}
/* select a "subminor" number (part of a minor number) */
mutex_lock(&minor_table_mutex);
for (minor = 0; minor < MAX_DEVICES; ++minor) {
if (minor_table[minor] == NULL)
break;
}
if (minor >= MAX_DEVICES) {
printk(KERN_INFO "Too many devices plugged in, "
"can not handle this device.\n");
goto error;
}
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(struct mceusb_device), GFP_KERNEL);
if (dev == NULL) {
err("Out of memory");
#ifdef KERNEL_2_5
retval = -ENOMEM;
#endif
goto error;
}
minor_table[minor] = dev;
mutex_init(&dev->lock);
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, 5)
iface_desc = &interface->altsetting[0];
#else
iface_desc = interface->cur_altsetting;
#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,
GFP_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,
GFP_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);
dev->write_urb->transfer_dma = dev->dma_out;
dev->write_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
#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 driver */
driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
if (!driver) {
err("out of memory");
goto error;
}
strcpy(driver->name, DRIVER_NAME " ");
driver->minor = minor;
driver->code_length = sizeof(lirc_t) * 8;
driver->features = LIRC_CAN_REC_MODE2; /* | LIRC_CAN_SEND_MODE2; */
driver->data = dev;
driver->buffer_size = 128;
driver->set_use_inc = &set_use_inc;
driver->set_use_dec = &set_use_dec;
driver->sample_rate = 80; /* sample at 100hz (10ms) */
driver->add_to_buf = &mceusb_add_to_buf;
#ifdef LIRC_HAVE_SYSFS
driver->dev = &interface->dev;
#endif
driver->owner = THIS_MODULE;
if (lirc_register_driver(driver) < 0) {
kfree(driver);
goto error;
}
dev->driver = driver;
/*
* 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
*/
for (i = 0; i < 40; i++)
(void) usb_bulk_msg(udev,
usb_rcvbulkpipe(udev,
dev->bulk_in_endpointAddr),
junk, 64, &partial, HZ*10);
msir_cleanup(dev);
mceusb_setup(udev);
#ifdef KERNEL_2_5
/* we can register the device now, as it is ready */
usb_set_intfdata(interface, dev);
#endif
mutex_unlock(&minor_table_mutex);
#ifdef KERNEL_2_5
return 0;
#else
return dev;
#endif
error:
if (likely(dev))
mceusb_delete(dev);
dev = NULL;
dprintk("%s: retval = %x", __func__, retval);
mutex_unlock(&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.
*
*/
#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 mceusb_device *dev;
int minor;
#ifdef KERNEL_2_5
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
#else
dev = (struct mceusb_device *)ptr;
#endif
mutex_lock(&minor_table_mutex);
mutex_lock(&dev->lock);
minor = dev->minor;
/* unhook lirc things */
lirc_unregister_driver(minor);
lirc_buffer_free(dev->driver->rbuf);
kfree(dev->driver->rbuf);
kfree(dev->driver);
mutex_unlock(&dev->lock);
mceusb_delete(dev);
printk(KERN_INFO "Microsoft IR Transceiver #%d now disconnected\n",
minor);
mutex_unlock(&minor_table_mutex);
}
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
}
printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");
return 0;
}
static void __exit usb_mceusb_exit(void)
{
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, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
EXPORT_NO_SYMBOLS;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,410 @@
/*
* lirc_ttusbir.c
*
* lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver
*
* Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de>
*
* This LIRC driver provides access to the TechnoTrend USB IR Receiver.
* The receiver delivers the IR signal as raw sampled true/false data in
* isochronous USB packets each of size 128 byte.
* Currently the driver reduces the sampling rate by factor of 8 as this
* is still more than enough to decode RC-5 - others should be analyzed.
* But the driver does not rely on RC-5 it should be able to decode every
* IR signal that is not too fast.
*/
/*
* 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
*/
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/lirc.h>
#include "kcompat.h"
#include "lirc_dev.h"
MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC");
MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)");
MODULE_LICENSE("GPL");
/* #define DEBUG */
#ifdef DEBUG
#define DPRINTK printk
#else
#define DPRINTK(_x_, a...)
#endif
/* function declarations */
static int probe(struct usb_interface *intf, const struct usb_device_id *id);
static void disconnect(struct usb_interface *intf);
#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
static void urb_complete(struct urb *urb, struct pt_regs *pt_regs);
#else
static void urb_complete(struct urb *urb);
#endif
static int set_use_inc(void *data);
static void set_use_dec(void *data);
static int num_urbs = 2;
module_param(num_urbs, int, S_IRUGO);
MODULE_PARM_DESC(num_urbs,
"Number of URBs in queue. Try to increase to 4 in case "
"of problems (default: 2; minimum: 2)");
/* table of devices that work with this driver */
static struct usb_device_id device_id_table[] = {
/* TechnoTrend USB IR Receiver */
{ USB_DEVICE(0x0B48, 0x2003) },
/* Terminating entry */
{ }
};
MODULE_DEVICE_TABLE(usb, device_id_table);
/* USB driver definition */
static struct usb_driver usb_driver = {
.name = "TTUSBIR",
.id_table = &(device_id_table[0]),
.probe = probe,
.disconnect = disconnect,
};
/* USB device definition */
struct ttusbir_device {
struct usb_driver *usb_driver;
struct usb_device *udev;
struct usb_interface *interf;
struct usb_class_driver class_driver;
unsigned int ifnum; /* Interface number to use */
unsigned int alt_setting; /* alternate setting to use */
unsigned int endpoint; /* Endpoint to use */
struct urb **urb; /* num_urb URB pointers*/
char **buffer; /* 128 byte buffer for each URB */
struct lirc_buffer rbuf; /* Buffer towards LIRC */
struct lirc_driver driver;
int minor;
int last_pulse; /* remembers if last received byte was pulse or space */
int last_num; /* remembers how many last bytes appeared */
int opened;
};
/*** LIRC specific functions ***/
static int set_use_inc(void *data)
{
int i, retval;
struct ttusbir_device *ttusbir = data;
DPRINTK("Sending first URBs\n");
/* @TODO Do I need to check if I am already opened */
ttusbir->opened = 1;
for (i = 0; i < num_urbs; i++) {
retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
if (retval) {
err("%s: usb_submit_urb failed on urb %d",
__func__, i);
return retval;
}
}
return 0;
}
static void set_use_dec(void *data)
{
struct ttusbir_device *ttusbir = data;
DPRINTK("Device closed\n");
ttusbir->opened = 0;
}
/*** USB specific functions ***/
/*
* This mapping table is used to do a very simple filtering of the
* input signal.
* For a value with at least 4 bits set it returns 0xFF otherwise
* 0x00. For faster IR signals this can not be used. But for RC-5 we
* still have about 14 samples per pulse/space, i.e. we sample with 14
* times higher frequency than the signal frequency
*/
const unsigned char map_table[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
static void urb_complete(struct urb *urb, struct pt_regs *pt_regs)
#else
static void urb_complete(struct urb *urb)
#endif
{
struct ttusbir_device *ttusbir;
unsigned char *buf;
int i;
lirc_t l;
ttusbir = urb->context;
if (!ttusbir->opened)
return;
buf = (unsigned char *)urb->transfer_buffer;
for (i = 0; i < 128; i++) {
/* Here we do the filtering and some kind of down sampling */
buf[i] = ~map_table[buf[i]];
if (ttusbir->last_pulse == buf[i]) {
if (ttusbir->last_num < PULSE_MASK/63)
ttusbir->last_num++;
/*
* else we are in a idle period and do not need to
* increment any longer
*/
} else {
l = ttusbir->last_num * 62; /* about 62 = us/byte */
if (ttusbir->last_pulse) /* pulse or space? */
l |= PULSE_BIT;
if (!lirc_buffer_full(&ttusbir->rbuf)) {
lirc_buffer_write(&ttusbir->rbuf, (void *)&l);
wake_up_interruptible(&ttusbir->rbuf.wait_poll);
}
ttusbir->last_num = 0;
ttusbir->last_pulse = buf[i];
}
}
usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */
}
/*
* Called whenever the USB subsystem thinks we could be the right driver
* to handle this device
*/
static int probe(struct usb_interface *intf, const struct usb_device_id *id)
{
int alt_set, endp;
int found = 0;
int i, j;
int struct_size;
struct usb_host_interface *host_interf;
struct usb_interface_descriptor *interf_desc;
struct usb_host_endpoint *host_endpoint;
struct ttusbir_device *ttusbir;
DPRINTK("Module ttusbir probe\n");
/* To reduce memory fragmentation we use only one allocation */
struct_size = sizeof(struct ttusbir_device) +
(sizeof(struct urb *) * num_urbs) +
(sizeof(char *) * num_urbs) +
(num_urbs * 128);
ttusbir = kzalloc(struct_size, GFP_KERNEL);
if (!ttusbir)
return -ENOMEM;
ttusbir->urb = (struct urb **)((char *)ttusbir +
sizeof(struct ttusbir_device));
ttusbir->buffer = (char **)((char *)ttusbir->urb +
(sizeof(struct urb *) * num_urbs));
for (i = 0; i < num_urbs; i++)
ttusbir->buffer[i] = (char *)ttusbir->buffer +
(sizeof(char *)*num_urbs) + (i * 128);
ttusbir->usb_driver = &usb_driver;
ttusbir->alt_setting = -1;
/* @TODO check if error can be returned */
ttusbir->udev = usb_get_dev(interface_to_usbdev(intf));
ttusbir->interf = intf;
ttusbir->last_pulse = 0x00;
ttusbir->last_num = 0;
/*
* Now look for interface setting we can handle
* We are searching for the alt setting where end point
* 0x82 has max packet size 16
*/
for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) {
host_interf = &intf->altsetting[alt_set];
interf_desc = &host_interf->desc;
for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) {
host_endpoint = &host_interf->endpoint[endp];
if ((host_endpoint->desc.bEndpointAddress == 0x82) &&
(host_endpoint->desc.wMaxPacketSize == 0x10)) {
ttusbir->alt_setting = alt_set;
ttusbir->endpoint = endp;
found = 1;
break;
}
}
}
if (ttusbir->alt_setting != -1)
DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
else {
err("Could not find alternate setting\n");
kfree(ttusbir);
return -EINVAL;
}
/* OK lets setup this interface setting */
usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting);
/* Store device info in interface structure */
usb_set_intfdata(intf, ttusbir);
/* Register as a LIRC driver */
if (lirc_buffer_init(&ttusbir->rbuf, sizeof(lirc_t), 256) < 0) {
err("Could not get memory for LIRC data buffer\n");
usb_set_intfdata(intf, NULL);
kfree(ttusbir);
return -ENOMEM;
}
strcpy(ttusbir->driver.name, "TTUSBIR");
ttusbir->driver.minor = -1;
ttusbir->driver.code_length = 1;
ttusbir->driver.sample_rate = 0;
ttusbir->driver.data = ttusbir;
ttusbir->driver.add_to_buf = NULL;
#ifndef LIRC_REMOVE_DURING_EXPORT
ttusbir->driver.get_queue = NULL;
#endif
ttusbir->driver.rbuf = &ttusbir->rbuf;
ttusbir->driver.set_use_inc = set_use_inc;
ttusbir->driver.set_use_dec = set_use_dec;
ttusbir->driver.fops = NULL;
ttusbir->driver.dev = &intf->dev;
ttusbir->driver.owner = THIS_MODULE;
ttusbir->driver.features = LIRC_CAN_REC_MODE2;
ttusbir->minor = lirc_register_driver(&ttusbir->driver);
if (ttusbir->minor < 0) {
err("Error registering as LIRC driver\n");
usb_set_intfdata(intf, NULL);
lirc_buffer_free(&ttusbir->rbuf);
kfree(ttusbir);
return -EIO;
}
/* Allocate and setup the URB that we will use to talk to the device */
for (i = 0; i < num_urbs; i++) {
ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
if (!ttusbir->urb[i]) {
err("Could not allocate memory for the URB\n");
for (j = i - 1; j >= 0; j--)
kfree(ttusbir->urb[j]);
lirc_buffer_free(&ttusbir->rbuf);
lirc_unregister_driver(ttusbir->minor);
kfree(ttusbir);
usb_set_intfdata(intf, NULL);
return -ENOMEM;
}
ttusbir->urb[i]->dev = ttusbir->udev;
ttusbir->urb[i]->context = ttusbir;
ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev,
ttusbir->endpoint);
ttusbir->urb[i]->interval = 1;
ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP;
ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0];
ttusbir->urb[i]->complete = urb_complete;
ttusbir->urb[i]->number_of_packets = 8;
ttusbir->urb[i]->transfer_buffer_length = 128;
for (j = 0; j < 8; j++) {
ttusbir->urb[i]->iso_frame_desc[j].offset = j*16;
ttusbir->urb[i]->iso_frame_desc[j].length = 16;
}
}
return 0;
}
/**
* Called when the driver is unloaded or the device is unplugged
*/
static void disconnect(struct usb_interface *intf)
{
int i;
struct ttusbir_device *ttusbir;
DPRINTK("Module ttusbir disconnect\n");
ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
lirc_unregister_driver(ttusbir->minor);
DPRINTK("unregistered\n");
for (i = 0; i < num_urbs; i++) {
usb_kill_urb(ttusbir->urb[i]);
usb_free_urb(ttusbir->urb[i]);
}
DPRINTK("URBs killed\n");
lirc_buffer_free(&ttusbir->rbuf);
kfree(ttusbir);
}
static int ttusbir_init_module(void)
{
int result;
DPRINTK(KERN_DEBUG "Module ttusbir init\n");
/* register this driver with the USB subsystem */
result = usb_register(&usb_driver);
if (result)
err("usb_register failed. Error number %d", result);
return result;
}
static void ttusbir_exit_module(void)
{
printk(KERN_DEBUG "Module ttusbir exit\n");
usb_deregister(&usb_driver);
}
module_init(ttusbir_init_module);
module_exit(ttusbir_exit_module);