⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lirc_gpio.c

📁 很少见的linux下的红外口的工具
💻 C
字号:
/* * Remote control driver for the TV-card * key codes are obtained from GPIO port *  * (L) by Artur Lipowski <alipowski@kki.net.pl> *     patch for the AverMedia by Santiago Garcia Mantinan <manty@i.am> *                            and Christoph Bartelmus <lirc@bartelmus.de> *     patch for the BestBuy by Miguel Angel Alvarez <maacruz@navegalia.com> *     patch for the Winfast TV2000 by Juan Toledo <toledo@users.sourceforge.net> * *  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 * * $Id: lirc_gpio.c,v 1.16 2002/08/30 11:57:28 lirc Exp $ * */#include <linux/version.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 4)#error "*******************************************************"#error "Sorry, this driver needs kernel version 2.2.4 or higher"#error "*******************************************************"#endif#include <linux/module.h>#include <linux/kmod.h>#include <linux/sched.h>#include <linux/wrapper.h>#include <linux/errno.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)/* comes with bttv */#include "../drivers/char/kcompat24.h"#include "../drivers/char/bttv.h"#include "../drivers/char/bttvp.h"#else#include "../drivers/media/video/bttv.h"#include "../drivers/media/video/bttvp.h"#endif#if BTTV_VERSION_CODE < KERNEL_VERSION(0,7,45)#error "*******************************************************"#error " Sorry, this driver needs bttv version 0.7.45 or       "#error " higher. If you are using the bttv package, copy it to "#error " the kernel                                            "#error "*******************************************************"#endif#include "../lirc_dev/lirc_dev.h"static int debug = 0;static int card = 0;static int minor = -1;static unsigned long gpio_mask = 0;static unsigned long gpio_enable = 0;static unsigned long gpio_lock_mask = 0;static unsigned long gpio_xor_mask = 0;static unsigned int soft_gap = 0;static unsigned char sample_rate = 10;MODULE_PARM(debug,"i");MODULE_PARM(card,"i");MODULE_PARM(minor,"i");MODULE_PARM(gpio_mask,"l");MODULE_PARM(gpio_lock_mask,"l");MODULE_PARM(gpio_xor_mask,"l");MODULE_PARM(soft_gap,"i");MODULE_PARM(sample_rate,"b");#define dprintk  if (debug) printkstruct rcv_info {	int bttv_id;	int card_id;	unsigned long gpio_mask;	unsigned long gpio_enable;	unsigned long gpio_lock_mask;	unsigned long gpio_xor_mask;	unsigned int soft_gap;	unsigned char sample_rate;	unsigned char code_length;};static struct rcv_info rcv_infos[] = {	{BTTV_UNKNOWN,                0,          0,          0,         0,          0,   0,  1,  0},#ifdef BTTV_PXELVWPLTVPAK	{BTTV_PXELVWPLTVPAK,          0, 0x00003e00,          0, 0x0010000,          0,   0, 15,  0},#endif	{BTTV_PXELVWPLTVPRO,          0, 0x00001f00,          0, 0x0008000,          0, 500, 12, 32},#ifdef BTTV_PV_BT878P_9B	{BTTV_PV_BT878P_9B,           0, 0x00001f00,          0, 0x0008000,          0, 500, 12, 32},#endif	{BTTV_AVERMEDIA,              0, 0x00f88000,          0, 0x0010000, 0x00010000,   0, 10, 32},	{BTTV_AVPHONE98,     0x00011461, 0x003b8000, 0x00004000, 0x0800000, 0x00800000,   0, 10,  0}, /*mapped to Capture98*/	{BTTV_AVERMEDIA98,   0x00021461, 0x003b8000, 0x00004000, 0x0800000, 0x00800000,   0, 10,  0}, /*mapped to Capture98*/	{BTTV_AVPHONE98,     0x00031461, 0x00f88000,          0, 0x0010000, 0x00010000,   0, 10, 32}, /*mapped to Phone98*/	/* is this one correct? */	{BTTV_AVERMEDIA98,   0x00041461, 0x00f88000,          0, 0x0010000, 0x00010000,   0, 10, 32}, /*mapped to Phone98*/	{BTTV_CHRONOS_VS2,            0, 0x000000f8,          0, 0x0000100,          0,   0, 20,  0},	/* CPH031 and CPH033 cards (?) */	/* MIRO was just a work-around */	{BTTV_MIRO,                   0, 0x00001f00,          0, 0x0004000,          0,   0, 10, 32},	{BTTV_DYNALINK,               0, 0x00001f00,          0, 0x0004000,          0,   0, 10, 32},	/* just a guess */	{BTTV_MAGICTVIEW061,          0, 0x0028e000,          0, 0x0020000,          0,   0, 20, 32}, 	{BTTV_MAGICTVIEW063,          0, 0x0028e000,          0, 0x0020000,          0,   0, 20, 32}, 	{BTTV_PHOEBE_TVMAS,           0, 0x0028e000,          0, 0x0020000,          0,   0, 20, 32},#ifdef BTTV_BESTBUY_EASYTV2        {BTTV_BESTBUY_EASYTV,         0, 0x00007F00,          0, 0x0004000,          0,   0, 10,  8},        {BTTV_BESTBUY_EASYTV2,        0, 0x00007F00,          0, 0x0008000,          0,   0, 10,  8},#endif	{BTTV_FLYVIDEO,               0, 0x000000ff,          0,         0,          0,   0,  0, 42},	/* probably                      0x000000f8 */ 	{BTTV_FLYVIDEO_98,            0, 0x000001f8,          0, 0x0000100,          0,   0,  0,  0},#ifdef BTTV_FLYVIDEO_98FM	/* smorar@alfonzo.smuts.uct.ac.za */	/* probably                      0x000000f8 */ 	{BTTV_FLYVIDEO_98FM,          0, 0x000001f8,          0, 0x0000100,          0,   0,  0,  0},#endif        {BTTV_WINFAST2000,            0, 0x000000f8,          0, 0x0000100,          0,   0,  0,  0}};static unsigned char code_length = 0;static unsigned char code_bytes = 1;static int card_type = 0;#define MAX_BYTES 8#define SUCCESS 0#define LOGHEAD "lirc_gpio (%d): "/* how many bits GPIO value can be shifted right before processing * it is computed from the value of gpio_mask_parameter */static unsigned char gpio_pre_shift = 0;static inline int reverse(int data, int bits){	int i;	int c;		for (c=0,i=0; i<bits; i++) {		c |= (((data & (1<<i)) ? 1:0)) << (bits-1-i);	}	return c;}static int build_key(unsigned long gpio_val, unsigned char codes[MAX_BYTES]){	unsigned long mask = gpio_mask;	unsigned char shift = 0;	dprintk(LOGHEAD "gpio_val is %lx\n",card,(unsigned long) gpio_val);		gpio_val ^= gpio_xor_mask;		if (gpio_lock_mask && (gpio_val & gpio_lock_mask)) {		return -EBUSY;	}	switch (rcv_infos[card_type].bttv_id)	{	case BTTV_AVERMEDIA98:		if (bttv_write_gpio(card, gpio_enable, gpio_enable)) {			dprintk(LOGHEAD "cannot write to GPIO\n", card);			return -EIO;		}		if (bttv_read_gpio(card, &gpio_val)) {			dprintk(LOGHEAD "cannot read GPIO\n", card);			return -EIO;		}		if (bttv_write_gpio(card, gpio_enable, 0)) {			dprintk(LOGHEAD "cannot write to GPIO\n", card);			return -EIO;		}		break;	default:		break;	}		/* extract bits from "raw" GPIO value using gpio_mask */	codes[0] = 0;	gpio_val >>= gpio_pre_shift;	while (mask) {		if (mask & 1u) {			codes[0] |= (gpio_val & 1u) << shift++;		}		mask >>= 1;		gpio_val >>= 1;	}		dprintk(LOGHEAD "code is %lx\n",card,(unsigned long) codes[0]);	switch (rcv_infos[card_type].bttv_id)	{	case BTTV_AVERMEDIA:		codes[2] = (codes[0]<<2)&0xff;		codes[3] = (~codes[2])&0xff;		codes[0] = 0x02;		codes[1] = 0xFD;		break;	case BTTV_AVPHONE98:		codes[2] = ((codes[0]&(~0x1))<<2)&0xff;		codes[3] = (~codes[2])&0xff;		if (codes[0]&0x1) {			codes[0] = 0xc0;			codes[1] = 0x3f;		} else {			codes[0] = 0x40;			codes[1] = 0xbf;		}		break;	case BTTV_AVERMEDIA98:		break;	case BTTV_FLYVIDEO:		codes[5]=codes[0];		codes[0]=0x03;		codes[1]=0xE5;		codes[2]=0xE0;		codes[3]=0xD0;		codes[4]=((~codes[0])&0xff);		break;        case BTTV_MAGICTVIEW061:        case BTTV_MAGICTVIEW063:	case BTTV_PHOEBE_TVMAS:		codes[0] = (codes[0]&0x01)			|((codes[0]&0x02)<<1)			|((codes[0]&0x04)<<2)			|((codes[0]&0x08)>>2)			|((codes[0]&0x10)>>1);		/* FALLTHROUGH */	case BTTV_MIRO:	case BTTV_DYNALINK:	case BTTV_PXELVWPLTVPRO:#ifdef BTTV_PV_BT878P_9B	case BTTV_PV_BT878P_9B:#endif		codes[2] = reverse(codes[0],8);		codes[3] = (~codes[2])&0xff;		codes[0] = 0x61;		codes[1] = 0xD6;		break;#if 0		/* derived from e-tech config file */		/* 26 + 16 bits */		/* won't apply it until it's confirmed with a fly98 */ 	case BTTV_FLYVIDEO_98:	case BTTV_FLYVIDEO_98FM:		codes[4]=codes[0]<<3;		codes[5]=(~codes[4])&0xff;				codes[0]=0x00;		codes[1]=0x1A;		codes[2]=0x1F;		codes[3]=0x2F;		break;#endif	default:		break;	}	return SUCCESS;}static int get_key(void* data, unsigned char *key, int key_no){	static unsigned long next_time = 0;	static unsigned char codes[MAX_BYTES];	unsigned long code = 0;	unsigned char cur_codes[MAX_BYTES];		if (key_no > 0)	{		if (code_bytes < 2 || key_no >= code_bytes) {			dprintk(LOGHEAD "something wrong in get_key\n", card);			return -EBADRQC;		}		*key = codes[key_no];		return SUCCESS;	}		if (bttv_read_gpio(card, &code)) {		dprintk(LOGHEAD "cannot read GPIO\n", card);		return -EIO;	}	if (build_key(code, cur_codes)) {		return -EFAULT;	}	if (soft_gap) {		if (!memcmp(codes, cur_codes, code_bytes) && 		    jiffies < next_time) {			return -EAGAIN;		}		next_time = jiffies + soft_gap;	}	memcpy(codes, cur_codes, code_bytes);	*key = codes[0];	return SUCCESS;}static void set_use_inc(void* data){	MOD_INC_USE_COUNT;}static void set_use_dec(void* data){	MOD_DEC_USE_COUNT;}static wait_queue_head_t* get_queue(void* data){	return bttv_get_gpio_queue(card);}static struct lirc_plugin plugin = {	"lirc_gpio  ",	0,	0,	0,	NULL,	get_key,	get_queue,	set_use_inc,	set_use_dec};/* * */int gpio_remote_init(void){  		int ret;	unsigned int mask;	/* "normalize" gpio_mask	 * this means shift it right until first bit is set	 */	while (!(gpio_mask & 1u)) {		gpio_pre_shift++;		gpio_mask >>= 1;	}	if (code_length) {		plugin.code_length = code_length;	} else {		/* calculate scan code length in bits if needed */		plugin.code_length = 1;		mask = gpio_mask >> 1;		while (mask) {			if (mask & 1u) {				plugin.code_length++;			}			mask >>= 1;		}	}	code_bytes = (plugin.code_length/8) + (plugin.code_length%8 ? 1 : 0);	if (MAX_BYTES < code_bytes) {		printk (LOGHEAD "scan code too long (%d bytes)\n",			minor, code_bytes);		return -EBADRQC;	}	if (gpio_enable) {		if(bttv_gpio_enable(card, gpio_enable, gpio_enable)) {			printk(LOGHEAD "gpio_enable failure\n", minor);			return -EIO;		}	}	/* translate ms to jiffies */	soft_gap = (soft_gap*HZ) / 1000;	plugin.minor = minor;	plugin.sample_rate = sample_rate;	ret = lirc_register_plugin(&plugin);		if (0 > ret) {		printk (LOGHEAD "device registration failed with %d\n",			minor, ret);		return ret;	}		minor = ret;	printk(LOGHEAD "driver registered\n", minor);	return SUCCESS;}EXPORT_NO_SYMBOLS; /* Dont try to use it as a static version !  */#ifdef MODULEMODULE_DESCRIPTION("Driver module for remote control (data from bt848 GPIO port)");MODULE_AUTHOR("Artur Lipowski");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endif/* * */int init_module(void){	int type,cardid;	if (MAX_IRCTL_DEVICES < minor) {		printk("lirc_gpio: parameter minor (%d) must be less than %d!\n",		       minor, MAX_IRCTL_DEVICES-1);		return -EBADRQC;	}		request_module("bttv");	/* if gpio_mask not zero then use module parameters 	 * instead of autodetecting TV card	 */	if (gpio_mask) {		if (2 > sample_rate || 50 < sample_rate) {			printk(LOGHEAD "parameter sample_rate "			       "must be beetween 2 and 50!\n", minor);			return -EBADRQC;		}		if (soft_gap && 		    ((2000/sample_rate) > soft_gap || 1000 < soft_gap)) {			printk(LOGHEAD "parameter soft_gap "			       "must be beetween %d and 1000!\n",			       minor, 2000/sample_rate);			return -EBADRQC;		}	} else {		if(bttv_get_cardinfo(card,&type,&cardid)==-1) {			printk(LOGHEAD "could not get card type\n", minor);		}		printk(LOGHEAD "card type 0x%x, id 0x%x\n",minor,		       type,cardid);		if (type == BTTV_UNKNOWN) {			printk(LOGHEAD "cannot detect TV card nr %d!\n",			       minor, card);			return -EBADRQC;		}		for (card_type = 1;		     card_type < sizeof(rcv_infos)/sizeof(struct rcv_info); 		     card_type++) {			if (rcv_infos[card_type].bttv_id == type &&			    (rcv_infos[card_type].card_id == 0 ||			     rcv_infos[card_type].card_id == cardid)) {				gpio_mask = rcv_infos[card_type].gpio_mask;				gpio_enable = rcv_infos[card_type].gpio_enable;				gpio_lock_mask = rcv_infos[card_type].gpio_lock_mask;				gpio_xor_mask = rcv_infos[card_type].gpio_xor_mask;				soft_gap = rcv_infos[card_type].soft_gap;				sample_rate = rcv_infos[card_type].sample_rate;				code_length = rcv_infos[card_type].code_length;				break;			}		}		if (type==BTTV_AVPHONE98 && cardid==0x00011461)	{			rcv_infos[card_type].bttv_id = BTTV_AVERMEDIA98;		}		if (type==BTTV_AVERMEDIA98 && cardid==0x00041461) {			rcv_infos[card_type].bttv_id = BTTV_AVPHONE98;		}		if (card_type == sizeof(rcv_infos)/sizeof(struct rcv_info)) {			printk(LOGHEAD "TV card type %x not supported!\n",			       minor, type);			return -EBADRQC;		}	}	request_module("lirc_dev");	return gpio_remote_init();}/* * */void cleanup_module(void){	int ret;	ret = lirc_unregister_plugin(minor); 	if (0 > ret) {		printk(LOGHEAD "error in lirc_unregister_minor: %d\n"		       "Trying again...\n",		       minor, ret);		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(HZ);		ret = lirc_unregister_plugin(minor); 		if (0 > ret) {			printk(LOGHEAD "error in lirc_unregister_minor: %d!!!\n",			       minor, ret);			return;		}	}	dprintk(LOGHEAD "module successfully unloaded\n", minor);}#endif/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -