Mailing List archive

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

[linux-dvb] Re: TT budget / NOVA IR support



Hi Jack,

I'd like to apply your patch, but please modify it in order to follow the Linux kernel coding style rules in /usr/src/linux/Documentation/CodingStyle.

And please prepare 2 patches, one against the DVB/-Tree and one against dvb-kernel/.

many thanks,

Holger



Jack Thomasson wrote:
the attached patch adds IR support for TT-PCline budget / Hauppauge
WinTV-Nova cards using MSP430 microcontrollers. i developed against a
WinTV-Nova-CI-s but there may be other cards as well. you'll find the
microcontroller just below the IR header (a sub-mini phono socket)
labelled MSP430F1101.

enjoy,

:{)}


------------------------------------------------------------------------

diff -u -r1.7 Makefile
--- DVB/driver/av7110/Makefile 8 Nov 2002 15:28:08 -0000 1.7
+++ DVB/driver/av7110/Makefile 16 Jan 2003 22:26:33 -0000
@@ -23,6 +23,7 @@
else
obj-$(CONFIG_AV7110_DVB) += dvb-ttpci.o
endif
+obj-m += msp430_ir.o
# Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's.

diff -u --unidirectional-new-file DVB-current/driver/av7110/msp430_ir.c DVB/driver/av7110/msp430_ir.c
--- DVB-current/driver/av7110/msp430_ir.c 1969-12-31 17:00:00.000000000 -0700
+++ DVB/driver/av7110/msp430_ir.c 2003-01-16 15:37:54.000000000 -0700
@@ -0,0 +1,287 @@
+/* Copyright (c) 2003 Helius, Inc. All Rights Reserved. */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include "input_fake.h"
+#endif
+
+#include "saa7146_defs.h"
+#include "saa7146_core.h"
+
+MODULE_AUTHOR("Helius, Inc.");
+MODULE_DESCRIPTION("input event module for those TechnoTrend TT-PCline budget/Hauppauge WinTV-Nova IR receivers using MSP430 microcontrollers");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
+/* from reading the following remotes:
+ Zenith Universal 7 / TV Mode 807 / VCR Mode 837
+ Hauppauge (from NOVA-CI-s box product)
+ i've taken a "middle of the road" approach and note the differences
+*/
+static u16 key_map[64] = {
+ /* 0x0X */
+ KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,
+ KEY_ENTER,
+ 0,
+ KEY_POWER, /* RADIO on Hauppauge */
+ KEY_MUTE,
+ 0,
+ KEY_A, /* TV on Hauppauge */
+ /* 0x1X */
+ KEY_VOLUMEUP, KEY_VOLUMEDOWN,
+ 0, 0,
+ KEY_B,
+ 0, 0, 0, 0, 0, 0, 0,
+ KEY_UP, KEY_DOWN,
+ KEY_OPTION, /* RESERVED on Hauppauge */
+ 0,
+ /* 0x2X */
+ KEY_CHANNELUP, KEY_CHANNELDOWN,
+ KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
+ 0, 0, 0,
+ KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
+ 0,
+ KEY_ENTER, /* VCR mode on Zenith */
+ KEY_PAUSE,
+ 0,
+ KEY_RIGHT, KEY_LEFT,
+ 0,
+ KEY_MENU, /* FULL SCREEN on Hauppauge */
+ 0,
+ /* 0x3X */
+ 0,
+ KEY_PREVIOUS, /* VCR mode on Zenith */
+ KEY_REWIND,
+ 0,
+ KEY_FASTFORWARD,
+ KEY_PLAY, KEY_STOP,
+ KEY_RECORD,
+ KEY_TUNER, /* TV/VCR on Zenith */
+ 0,
+ KEY_C,
+ 0,
+ KEY_EXIT,
+ 0,
+ KEY_TUNER, /* VCR mode on Zenith */
+ 0,
+};
+
+
+#define __COMPILE_SAA7146_STUFF__
+#include "saa7146.c"
+
+#ifndef BORROWED_FROM_AV7110_H_BUT_REALLY_BELONGS_IN_SAA7146_DEFS_H
+/* DEBI transfer mode defs */
+
+#define DEBINOSWAP 0x000e0000
+#define DEBISWAB 0x001e0000
+#define DEBISWAP 0x002e0000
+
+typedef enum GPIO_MODE
+{
+ GPIO_INPUT = 0x00,
+ GPIO_IRQHI = 0x10,
+ GPIO_IRQLO = 0x20,
+ GPIO_IRQHL = 0x30,
+ GPIO_OUTLO = 0x40,
+ GPIO_OUTHI = 0x50
+} GPIO_MODE;
+#endif
+
+
+#ifndef BORROWED_FROM_AV7110_C_BUT_REALLY_BELONGS_IN_SAA7146_CORE_C
+/* This DEBI code is based on the Stradis driver + by Nathan Laredo <laredo@gnu.org> */
+
+static
+int wait_for_debi_done(struct saa7146* saa)
+{
+ int start = jiffies;
+
+ /* wait for registers to be programmed */
+ while (1) {
+ if (saa7146_read(saa->mem, MC2) & 2)
+ break;
+ if (jiffies-start > HZ/20) {
+ printk (KERN_WARNING __FUNCTION__": timed out while waiting"
+ " for registers getting programmed\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* wait for transfer to complete */
+ start = jiffies;
+ while (1) {
+ if (!(saa7146_read(saa->mem, PSR) & SPCI_DEBI_S))
+ break;
+ saa7146_read(saa->mem, MC2);
+ if (jiffies-start > HZ/4) {
+ printk (KERN_WARNING __FUNCTION__": timed out while waiting"
+ " for transfer completion\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static inline u32 debiread(struct saa7146* saa, u32 config, int addr, int count)
+{
+ u32 result = 0;
+
+ if (count > 4 || count <= 0)
+ return 0;
+ if (wait_for_debi_done(saa) < 0)
+ return 0;
+ saa7146_write(saa->mem, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
+ saa7146_write(saa->mem, DEBI_CONFIG, config);
+ saa7146_write(saa->mem, MC2, (2 << 16) | 2);
+ wait_for_debi_done(saa);
+ result = saa7146_read(saa->mem, DEBI_AD);
+ result &= (0xffffffffUL >> ((4-count)*8));
+ return result;
+}
+
+/* DEBI during interrupt */
+
+static inline u32
+irdebi(struct saa7146* saa, u32 config, int addr, u32 val, int count)
+{
+ u32 res;
+ res=debiread(saa, config, addr, count);
+ return res;
+}
+#endif
+
+
+static void msp430_ir_debounce(unsigned long data) {
+ struct input_dev* dev = (struct input_dev*)data;
+ if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
+ input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); /* BREAK */
+ return;
+ }
+ dev->rep[0] = 0;
+ dev->timer.expires = jiffies + HZ * 350 / 1000;
+ add_timer(&dev->timer);
+ input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
+}
+
+
+static void msp430_ir_interrupt(struct saa7146* saa, u32 isr, void* data) {
+ unsigned int code = irdebi(saa, DEBINOSWAP, 0x1234, 0, 2) >> 8;
+ if (code & 0x40) {
+ struct input_dev* dev = (struct input_dev*)data;
+ code &= 0x3f;
+ if (timer_pending(&dev->timer)) {
+ if (code == dev->repeat_key) {
+ ++dev->rep[0];
+ return;
+ }
+ del_timer(&dev->timer);
+ input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); /* BREAK */
+ }
+ if (!key_map[code]) {
+ printk(KERN_ERR __FUNCTION__": no key for %02x!\n", code);
+ return;
+ }
+ /* initialize debounce and repeat */
+ dev->repeat_key = code;
+ dev->rep[0] = ~0; /* Zenith remote _always_ sends 2 sequences */
+ dev->timer.expires = jiffies + HZ * 350 / 1000; /* 350 milliseconds */
+ add_timer(&dev->timer);
+ input_event(dev, EV_KEY, key_map[code], !0); /* MAKE */
+ }
+}
+
+
+static int msp430_ir_attach(struct saa7146* saa, void** priv_ptr) {
+ struct input_dev* dev;
+ int n;
+
+ if (saa->card_type != DVB_CARD_TT_BUDGET_CI) {
+ printk(KERN_ERR __FUNCTION__": rejected %s type=%d\n", saa->name, saa->card_type);
+ return -ENOENT;
+ }
+
+ if ((dev = (struct input_dev*)kmalloc(sizeof(struct input_dev), GFP_KERNEL)) == 0) {
+ printk(KERN_ERR __FUNCTION__": OOM!\n");
+ return -ENOMEM;
+ }
+ memset(dev, 0, sizeof(*dev));
+ dev->name = saa->name;
+ set_bit(EV_KEY, dev->evbit);
+ for (n = sizeof(key_map) / sizeof(*key_map); --n >= 0; )
+ if (key_map[n])
+ set_bit(key_map[n], dev->keybit);
+ input_register_device(dev);
+ /* input_dev timer and repeat stuff used only if EV_REP, initialized above, reuse */
+ dev->timer.function = msp430_ir_debounce;
+ *priv_ptr = dev;
+
+ /* reset MSP430 */
+ gpio_set(saa, 3, GPIO_OUTLO);
+ gpio_set(saa, 2, GPIO_OUTLO);
+ udelay(1000); /* 1 millisecond */
+ saa7146_write(saa->mem, IER, saa7146_read(saa->mem, IER) | MASK_06);
+ gpio_set(saa, 3, GPIO_IRQHI);
+ gpio_set(saa, 2, GPIO_OUTHI);
+ printk(KERN_INFO "msp430_ir: attached %s\n", saa->name);
+ return 0;
+}
+
+
+static int msp430_ir_detach(struct saa7146* saa, void** priv_ptr) {
+ struct input_dev* dev = (struct input_dev*)*priv_ptr;
+ saa7146_write(saa->mem, IER, saa7146_read(saa->mem, IER) & ~MASK_06);
+ gpio_set(saa, 3, GPIO_INPUT);
+ gpio_set(saa, 2, GPIO_INPUT);
+ if (del_timer(&dev->timer))
+ input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); /* BREAK */
+ input_unregister_device(dev);
+ return 0;
+}
+
+
+static void msp430_ir_inc_use(struct saa7146* saa) {
+ MOD_INC_USE_COUNT;
+}
+
+
+static void msp430_ir_dec_use(struct saa7146* saa) {
+ MOD_DEC_USE_COUNT;
+}
+
+
+static struct saa7146_extension msp430_ir_extension = {
+ name: "msp430_ir",
+ handles_irqs: MASK_06,
+ irq_handler: msp430_ir_interrupt,
+ attach: msp430_ir_attach,
+ detach: msp430_ir_detach,
+ inc_use: msp430_ir_inc_use,
+ dec_use: msp430_ir_dec_use,
+};
+
+
+static int __init msp430_ir_init(void) {
+ int ret;
+ printk(KERN_INFO "msp430_ir: Copyright (c) 2003 Helius, Inc. All Rights Reserved.\n");
+
+ if ((ret = saa7146_add_extension(&msp430_ir_extension)))
+ printk(KERN_ERR "msp430_ir: add_extension failed with %d\n", ret);
+ return ret;
+}
+
+
+static void __exit msp430_ir_exit(void) {
+ int ret;
+ if ((ret = saa7146_del_extension(&msp430_ir_extension)))
+ printk(KERN_ERR "msp430_ir: del_extension failed with %d\n", ret);
+}
+
+module_init(msp430_ir_init);
+module_exit(msp430_ir_exit);




--
Info:
To unsubscribe send a mail to listar@linuxtv.org with "unsubscribe linux-dvb" as subject.



Home | Main Index | Thread Index