diff -Nru lirc-0.8.2/configure.in lirc-0.8.2-xilleon/configure.in --- lirc-0.8.2/configure.in 2007-06-09 18:54:09 +0000 +++ lirc-0.8.2-xilleon/configure.in 2010-08-25 18:25:10 +0000 @@ -179,7 +179,8 @@ (lirc_dev lirc_sasem) \ (lirc_dev lirc_serial) \ (lirc_dev lirc_sir) \ - (lirc_dev lirc_streamzap)" + (lirc_dev lirc_streamzap) \ + (lirc_dev lirc_xilleon)" fi if test -n "${LIBUSB_CONFIG}"; then @@ -282,7 +283,7 @@ sb0540, serial, silitek, sir, slinke, streamzap, tekram, tekram_bt829, tira, ttusbir, tuxbox, tvbox, udp, uirt2, - uirt2_raw, usb_uirt_raw, usbx], + uirt2_raw, usb_uirt_raw, usbx, xilleon], driver=${withval}, driver="unset" ) @@ -421,6 +422,8 @@ ;; lirc_dev-lirc_streamzap) ;; + lirc_dev-lirc_xilleon) + ;; lirc_flyvideo) ;; livedrive_midi) @@ -1125,6 +1128,10 @@ lircd_conf="adstech/lircd.conf.usbx-707" fi +if test "$driver" = "xilleon"; then + lirc_driver="lirc_dev lirc_xilleon" +fi + #END HARDWARE HEURISTIC if test "$driver" = "devinput"; then @@ -1221,7 +1228,8 @@ lirc_sasem \ lirc_serial \ lirc_sir \ - lirc_streamzap" + lirc_streamzap \ + lirc_xilleon" fi if kernel_module=$(expr "$lirc_driver" : 'lirc_dev \(.*\)'); then : @@ -1433,6 +1441,7 @@ drivers/lirc_serial/Makefile drivers/lirc_sir/Makefile drivers/lirc_streamzap/Makefile + drivers/lirc_xilleon/Makefile daemons/Makefile tools/Makefile doc/Makefile diff -Nru lirc-0.8.2/drivers/Makefile.am lirc-0.8.2-xilleon/drivers/Makefile.am --- lirc-0.8.2/drivers/Makefile.am 2007-05-26 13:30:51 +0000 +++ lirc-0.8.2-xilleon/drivers/Makefile.am 2010-08-25 18:18:08 +0000 @@ -23,7 +23,8 @@ lirc_serial \ lirc_sir \ lirc_streamzap \ - lirc_ttusbir + lirc_ttusbir \ + lirc_xilleon SUBDIRS = @lirc_driver@ diff -Nru lirc-0.8.2/drivers/lirc_xilleon/Makefile.am lirc-0.8.2-xilleon/drivers/lirc_xilleon/Makefile.am --- lirc-0.8.2/drivers/lirc_xilleon/Makefile.am 1970-01-01 00:00:00 +0000 +++ lirc-0.8.2-xilleon/drivers/lirc_xilleon/Makefile.am 2010-08-25 18:19:32 +0000 @@ -0,0 +1,13 @@ +## $Id: Makefile.am,v 5.14 2004/04/25 16:29:27 lirc Exp $ + +## Process this file with automake to produce Makefile.in + +## this is so that Automake includes the C compiling definitions, and +## includes the source files in the distribution. +EXTRA_PROGRAMS = automake_dummy +automake_dummy_SOURCES = lirc_xilleon.c + +## there is no *just* object file support in automake. This is close enough +module_DATA = lirc_xilleon.o + +include ../Makefile.common diff -Nru lirc-0.8.2/drivers/lirc_xilleon/lirc_xilleon.c lirc-0.8.2-xilleon/drivers/lirc_xilleon/lirc_xilleon.c --- lirc-0.8.2/drivers/lirc_xilleon/lirc_xilleon.c 1970-01-01 00:00:00 +0000 +++ lirc-0.8.2-xilleon/drivers/lirc_xilleon/lirc_xilleon.c 2010-08-25 21:34:41 +0000 @@ -0,0 +1,321 @@ +/* + * lirc_xilleon.c + * + * lirc_xilleon - Device driver for ATI Xilleon 210 UIRT, + * currently only receiving is supported + * written for LIRC 0.8.2 (Linux 2.4!) + * + * Copyright (C) 2010 Hans-Werner Hilse + * + * This driver re-uses code from the lirc_serial driver, which is + * + * Copyright (C) 1996,97 Ralph Metzler + * Copyright (C) 1998 Trent Piepho + * Copyright (C) 1998 Ben Pfaff + * Copyright (C) 1999 Christoph Bartelmus + * Copyright (C) 2007 Andrei Tanas (suspend/resume support) + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* the following headers are ATI Xilleon specific and only present in + * certain kernels specifically for this platform + */ +#include +#include +#include + +#include "drivers/lirc.h" +#include "drivers/kcompat.h" +#include "drivers/lirc_dev/lirc_dev.h" + +#ifndef MODULE +#error lirc_xilleon can currently only be built as a module +#endif + +#define LIRC_DRIVER_VERSION "0.0.1" +#define LIRC_DRIVER_NAME "lirc_xilleon" + +#define UIRT_RX_FIFO_SIZE 32 + +/* UIRT is driven by a 48MHz clock */ +#define CALC_MUL_TO_USEC(sample_div) (1000000 / (48000000 / sample_div)) + +static int irq = XILLEON_UIRT_INT; + +static int sample_div = 2400; /* -> 50us */ +static int timeout = 1000; /* I don't have any idea what the unit is. */ +static int fifo_threshold = 4; +static int mul_to_usec = CALC_MUL_TO_USEC(2400); +static int debug; + +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ + fmt, ## args); \ + } while (0) + + +/* This MUST be a power of two! It has to be larger than 1 as well. */ + +#define RBUF_LEN 256 + +static struct lirc_buffer rbuf; + +static void inline rbwrite(lirc_t l) +{ + if(lirc_buffer_full(&rbuf)) /* no new signals will be accepted */ + { + dprintk("Buffer overrun\n"); + return; + } + _lirc_buffer_write_1(&rbuf, (void *)&l); +} + +static int inline uirt_rcvr_fifo_count(void) +{ + return UIRT_RX_FIFO_SIZE - GETFLD_PCUIPAMM32(UIRT_STATUS, RCVR_FIFO_AVAIL); +} + +static int inline uirt_rcvr_fifo_read(void) +{ + return GETREG_PCUIPAMM32(UIRT_RCVR_FIFO); +} + +static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs) +{ + unsigned int sample; + unsigned int mode2; + + if (GETFLAG_PCUIPAMM32(UIRT_INTR_STATUS, RCVR_OVERRUN_STAT)) { + dprintk("hardware FIFO overrun\n"); + while (uirt_rcvr_fifo_count() > 0) + sample = uirt_rcvr_fifo_read(); + SETFLAG_PCUIPAMM32(UIRT_INTR_CNTL, RCVR_OVERRUN_CLR); + return IRQ_RETVAL(IRQ_HANDLED); + } + + /* maybe we can rely on these and even share our interrupt? */ + if (GETFLAG_PCUIPAMM32(UIRT_INTR_STATUS, RCVR_TIMEOUT_STAT)) + dprintk("timeout interrupt\n"); + + if (GETFLAG_PCUIPAMM32(UIRT_INTR_STATUS, RCVR_FIFO_STAT)) + dprintk("FIFO interrupt\n"); + + while (uirt_rcvr_fifo_count() > 0) + { + sample = uirt_rcvr_fifo_read(); + mode2 = sample & 0x7FFF; + if(mode2 != 0x7FFF) { /* no timeout */ + mode2 *= mul_to_usec; + + dprintk("RLE sample read from receiver: %s, " + "duration %d usecs.\n", + (sample & 0x8000) ? "pulse" : "space", mode2); + + rbwrite((sample & 0x8000) ? (mode2|PULSE_BIT) : mode2); + wake_up_interruptible(&rbuf.wait_poll); + } + } + + return IRQ_RETVAL(IRQ_HANDLED); +} + +static int set_use_inc(void *data) +{ + int result; + unsigned long flags; + + /* Init read buffer. */ + if (lirc_buffer_init(&rbuf, sizeof(lirc_t), RBUF_LEN) < 0) + return -ENOMEM; + + SETREG_PCUIPAMM32(UIRT_INTR_ENABLE, 0); + result = request_irq(irq, irq_handler, + SA_INTERRUPT, LIRC_DRIVER_NAME, NULL); + + switch (result) { + case -EBUSY: + printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); + lirc_buffer_free(&rbuf); + return -EBUSY; + case -EINVAL: + printk(KERN_ERR LIRC_DRIVER_NAME + ": Bad irq number or handler\n"); + lirc_buffer_free(&rbuf); + return -EINVAL; + default: + dprintk("Interrupt %d obtained\n", irq); + break; + }; + + /* Soft reset */ + SETFLAG_PCUIPAMM32(UIRT_CNTL, RCVR_SOFTRESET); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/25); + + /* Configure timeout */ + SETREG_PCUIPAMM32(UIRT_CNTL, timeout); + + /* Configure receiver */ + SETFLD_PCUIPAMM32(UIRT_SAMPLE_CLKDIV, RCVR_SAMPLE_DIV, sample_div); + SETREG_PCUIPAMM32(UIRT_RCVR_DEMOD_CNTL, 0); + SETREG_PCUIPAMM32(UIRT_RCVR_NOISE_CNTL, 0); + + SETREG_PCUIPAMM32(UIRT_RCVR_CNTL, 0); + /* Receiver start/stop mode: + automatically start when edge is detected, don't + stop. */ + SETFLD_PCUIPAMM32(UIRT_RCVR_CNTL, RCVR_START_STOP, 4); + SETFLAG_PCUIPAMM32(UIRT_RCVR_CNTL, RCVR_OVERRUN_CNTL); + /* Trigger interrupt when this many samples are in the + FIFO: */ + SETFLD_PCUIPAMM32(UIRT_RCVR_CNTL, RCVR_FIFO_THRESHOLD, + fifo_threshold); + /* Have the RLE timer immediately start counting from 0 at + a recognized edge: */ + SETFLD_PCUIPAMM32(UIRT_RCVR_CNTL, RCVR_SAMPLE_SYNC, 1); + + /* Configure interrupts */ + SETFLAG_PCUIPAMM32(UIRT_INTR_CNTL, RCVR_OVERRUN_CLR); + SETFLAG_PCUIPAMM32(UIRT_INTR_ENABLE, RCVR_FIFO_EN); + SETFLAG_PCUIPAMM32(UIRT_INTR_ENABLE, RCVR_OVERRUN_EN); + SETFLAG_PCUIPAMM32(UIRT_INTR_ENABLE, RCVR_TIMEOUT_EN); + + /* Enable interrupts */ + SETFLAG_PCUIPAMM32(UIRT_INTR_ENABLE, MASTER_EN); + + MOD_INC_USE_COUNT; + return 0; +} + +static void set_use_dec(void *data) +{ + free_irq(irq, NULL); + + dprintk("freed IRQ %d\n", irq); + lirc_buffer_free(&rbuf); + + MOD_DEC_USE_COUNT; +} + +static int init_port(void) +{ + /* eventually aquire io resource for write FIFO when we have TX */ + return 0; +} + +/* keep this to implement ioctl and maybe writes -- later. */ +static struct file_operations lirc_fops = {}; + +static struct lirc_plugin plugin = { + name: LIRC_DRIVER_NAME, + minor: -1, + code_length: 1, + sample_rate: 0, /* TODO: plug this into our implementation */ + data: NULL, + add_to_buf: NULL, + get_queue: NULL, + rbuf: &rbuf, + set_use_inc: set_use_inc, + set_use_dec: set_use_dec, + fops: &lirc_fops, + dev: NULL, + owner: THIS_MODULE, + features: LIRC_CAN_REC_MODE2, +}; + +int init_module(void) +{ + int result; + + mul_to_usec = CALC_MUL_TO_USEC(sample_div); + + result = init_port(); + if (result < 0) + goto exit_xilleon_exit; + + plugin.minor = lirc_register_plugin(&plugin); + if (plugin.minor < 0) { + printk(KERN_ERR LIRC_DRIVER_NAME + ": register_chrdev failed!\n"); + result = -EIO; + goto exit_release; + } + + printk(KERN_INFO + LIRC_DRIVER_NAME " " LIRC_DRIVER_VERSION " registered\n"); + + return 0; +exit_release: + /* eventually free io resource for write FIFO when we have TX */ +exit_xilleon_exit: + return result; +} + +void cleanup_module(void) +{ + lirc_unregister_plugin(plugin.minor); + /* eventually free io resource for write FIFO when we have TX */ + dprintk("cleaned up module\n"); +} + +MODULE_DESCRIPTION("Infra-red receiver driver for ATI Xilleon 210 platform's UIRT."); +MODULE_AUTHOR("Hans-Werner Hilse"); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +module_param(sample_div, int, S_IRUGO); +MODULE_PARM_DESC(sample_div, "Sample duration in n/48 us (default=2400, is 50us)"); + +module_param(fifo_threshold, int, S_IRUGO); +MODULE_PARM_DESC(fifo_threshold, "FIFO IRQ threshold in sample values (default=4, FIFO length is 32)"); + +module_param(timeout, int, S_IRUGO); +MODULE_PARM_DESC(timeout, "Timeout (what unit?!?) (default=1000)"); + +EXPORT_NO_SYMBOLS;