?? ir.c
字號:
/* Copyright 1996-1997, ESS Technology, Inc. */
/* SCCSID @(#)ir.c 1.57 10/6/98 */
/*
* This module is used to receive and transmit IR signals.
*
* Transmitting of IR in the current version is interrupt driven (it
* uses timer 1 to keep track of time).
*/
/*
* The current code supports:
* 1) New 3881/3883 style interrupt handling (when DSC_IRQ is defined.)
* 2) Original timer2 style interrupt handling (when DSC_IRQ is not
* defined.)
* 3) Andy's GAL solution (when IRQSHARE is defined.) This solution will
* be phased out.
* 4) A customer's glue logic solution (when CUST6 is defined.) This
* solution will be phased out.
* 5) WebDVD board's 8259 solution (when WEBDVD && SLAVE are defined.) This
* solution will be phased out.
*
* It also supports 3 styles of R/C: NEC, SANYO and PHILIPS.
*/
/* Add support for dvd slave */
#include "common.h"
#include "const.h"
#include "constvar.h"
#include "dsc.h"
#include "ioport.h"
#include "ir.h"
#include "mvd.h"
#include "timedef.h"
#include "util.h"
#ifdef IR
#ifdef TVM_MODULE
PRIVATE unsigned int IS_IRXOR_HIGH = 0;
#define SET_IRXOR {SET_EAUX6; IS_IRXOR_HIGH = 1;}
#define CLEAR_IRXOR {CLEAR_EAUX6; IS_IRXOR_HIGH = 0;}
#endif /* TVM_MODULE */
/************************************************************************
* Macros relate to remote control
************************************************************************/
#ifdef IR_PHILIPS
#define IR_SYSCODE 0x6
#endif /* IR_PHILIPS */
#ifdef IR_NEC
#define IR_SYSCODE 0x00ff
#endif
#ifdef IR_SANYO
#define IR_SYSCODE 0x0cc0
#endif
#define ASSIGN_SYSCODE sysIRcode = IR_SYSCODE
#ifdef DSC_IRQ
/* For the new style of IR handling (i.e. via 3881) */
/************************************************************************
* Local variables. *
************************************************************************/
PRIVATE unsigned short dataIR; /* System/customer IR code */
PRIVATE char cntIRbits = 0; /* Number of IR sys/cust. bits */
PRIVATE volatile char stateIR = IR_IDLE; /* IR state machine state */
PRIVATE char trigger_edge;
#ifdef IR_SANYO
PRIVATE unsigned short IR_sanyo_codebar;/* Sanyo IR only */
#endif /* IR_SAYNO */
#ifdef IRREP
PRIVATE unsigned char previous_data; /* Record the previous ID code */
#endif
/************************************************************************
* Local routines *
************************************************************************/
PRIVATE void IR_core_NEC(unsigned int, int);
PRIVATE void IR_core_Philips(unsigned int);
void IR_init()
{
ASSIGN_SYSCODE; /* Initialize IR system code */
CLEAR_IRXOR; /* Clear IR XOR (EAUX11 is active high!! */
#ifdef IR_SANYO
IR_sanyo_codebar = (~sysIRcode) & 0x1fff;
#endif /* IR_SANYO */
DSC_INIT_IR(1, DSC_FALLING_EDGE, 1); /* Start 3881 IR */
trigger_edge = 0;
mvd[riface_clear_dbgirq] = 0; /* Clear debug_irq */
enable_int(debug);
}
#if (IR_NEC || IR_SANYO)
PRIVATE void IR_core_NEC(width, overflow)
unsigned int width;
int overflow;
{
#define LEADER_MIN ir_tbl[0]
#define LEADER_MAX ir_tbl[1]
#define DATA_1_MIN ir_tbl[2]
#define DATA_1_MAX ir_tbl[3]
#define DATA_0_MIN ir_tbl[4]
#define DATA_0_MAX ir_tbl[5]
#ifdef IRREP
#define REPEAT_MIN ir_tbl[6]
#define REPEAT_MAX ir_tbl[7]
#endif IRREP
unsigned int *ir_tbl;
unsigned char data;
char reset = 0;
ir_tbl = T_IR_powerup_tbl;
/*
* If 3881's clock overflows, then reset. The only exception is
* when REP is considered!!
*/
reset = overflow;
if (stateIR == IR_CUSTOM) {
dataIR <<= 1;
if ((width >= DATA_1_MIN) && (width <= DATA_1_MAX)) {
dataIR |= 0x1;
} else if ((width < DATA_0_MIN) || (width > DATA_1_MAX)) {
#ifdef IR_NEC
reset = 1;
#endif /* IR_NEC */
#ifdef IR_SANYO
reset = 1; /* we do not care about repeat key for Sanyo yet */
#endif /* IR_SANYO */
}
cntIRbits++;
#ifdef IR_NEC
/* First 16 bits are syscode */
if ((cntIRbits == 16) && (dataIR != sysIRcode)) reset = 1;
if (cntIRbits == 24) {
data = dataIR & 0xff;
/* reverse data bits to fit look up table */
mvd[riface_reflect] = data;
data = mvd[riface_reflect];
#ifdef IRREP
previous_data = data;
#endif
codeIR = data | 0x100; /* Indicate a new code */
} else if (cntIRbits == 32) reset = 1;
#endif /* IR_NEC */
#ifdef IR_SANYO
if (cntIRbits == 13) {
dataIR &= 0x1fff;
if (dataIR != sysIRcode) reset = 1;
dataIR = 0;
} else if (cntIRbits == 26) {
unsigned short tmp = (~sysIRcode) & 0x1fff;
if (dataIR != tmp) reset = 1;
dataIR = 0;
} else if (cntIRbits == 34) {
data = dataIR;
mvd[riface_reflect] = data;
data = mvd[riface_reflect];
codeIR = data;
dataIR = 0;
} else if (cntIRbits == 42) {
data = dataIR;
mvd[riface_reflect] = data;
data = ~(mvd[riface_reflect]);
if (data == codeIR) {
codeIR = data | 0x100;
} else codeIR = 0;
reset = 1;
}
#endif /* IR_SANYO */
} else {
if ((width >= LEADER_MIN) && (width <= LEADER_MAX)) {
stateIR = IR_CUSTOM;
dataIR = cntIRbits = 0;
#ifdef IRREP
} else if ((width >= REPEAT_MIN) && (width <= REPEAT_MAX)) {
/* if the width is 2.25 ms, it is repeat code leader */
if (repeat_IRkey_allowed(previous_data))
codeIR = previous_data | 0x100; /* Indicate a new code */
#endif
} else reset = 1;
}
if (reset) {
/* Reset all, start from the very beginning */
stateIR = IR_IDLE;
}
}
#endif /* IR_NEC || IR_SANYO */
#ifdef IR_PHILIPS
PRIVATE unsigned int data_half = 0; /* Mark whether or nor have half_bit
data before edge of intr. coming*/
PRIVATE void IR_core_Philips(width)
unsigned int width;
{
unsigned int *ir_tbl;
int reset;
int is_half_bit;
int is_full_bit;
#define HALFBIT_MIN ir_tbl[0]
#define HALFBIT_MAX ir_tbl[1]
#define ONEBIT_MIN ir_tbl[2]
#define ONEBIT_MAX ir_tbl[3]
ir_tbl = T_IR_powerup_tbl;
reset = 0;
is_half_bit = (width >= HALFBIT_MIN) && (width <= HALFBIT_MAX);
is_full_bit = (width >= ONEBIT_MIN) && (width <= ONEBIT_MAX);
if (stateIR == IR_IDLE) {
/* We shall get a rising edge, since the first bit is fixed */
dataIR = 0;
cntIRbits = 0;
stateIR = IR_CUSTOM;
if (is_half_bit) data_half = 0;
else if (is_full_bit) data_half = 1;
else {
stateIR = IR_IDLE;
}
} else {
if (data_half) {
/*
* We were in half bit position, so this edge shall either
* conclude the previous cycle or go the the half position
* of the next bit. Record the last bit.
*/
dataIR <<= 1;
if (!trigger_edge) dataIR |= 1;
cntIRbits++;
if (is_half_bit) data_half = 0;
else if (!is_full_bit) reset = 1;
} else {
/*
* We started at a sampling cycle, so we shall only get half bit,
* otherwise, something is wrong!
*/
if (is_half_bit) data_half = 1;
else reset = 1;
}
if ((cntIRbits == 12) && trigger_edge && data_half) {
/* This is the last rising edge, no more. So collect the bit */
dataIR <<= 1;
dataIR |= 1;
cntIRbits = 13;
}
if (reset) {
/*
* Abnormal exist. Maybe we are out of sync. If this
* is falling edge, maybe this is the sync of a new
* input!
*/
stateIR = IR_IDLE;
if (trigger_edge) stateIR = IR_LEADER;
} else if (cntIRbits == 13) {
/* We only care the case when system code matches */
if (((dataIR >> 6) & 0x1f) == sysIRcode) {
unsigned int prevctlbit;
prevctlbit = IR_ctlbit;
IR_ctlbit = (dataIR >> 11) & 1;
if ((unsigned int) IR_ctlbit != prevctlbit) {
int tmp = (dataIR >> 12) & 1;
if (tmp) tmp = 0x40;
codeIR = (dataIR & 0x3f) | tmp | 0x100;
IR_rep_cnt = 0;
} else
IR_rep_cnt++;
IR_int_time = (unsigned int) mvd[riface_timer2];
}
stateIR = IR_IDLE;
}
}
}
#endif /* IR_PHILIPS */
/* Interrupt via 3881 */
void IR_recv_interrupt_service(status)
unsigned int status;
{
unsigned char width;
int overflow = 0;
int clear = 0x4;
if (status & 0x80) {
overflow = 1; /* 3881's clock overflowed */
clear = 0x84; /* Clear the overflow bit */
}
width = DSC_cmd(dsc_ir_diffm, 0); /* Get the counter */
DSC_cmd(dsc_sys_status, clear); /* Clear 3881's IR int */
mvd[riface_clear_dbgirq] = 0; /* Clear 3210's debug_irq */
#if (IR_NEC || IR_SANYO)
IR_core_NEC((unsigned int) width, overflow);
#endif /* IR_NEC || IR_SAYNO */
#ifdef IR_PHILIPS
if (!trigger_edge)
DSC_INIT_IR(1, DSC_RISING_EDGE, 0); /* detect rising edge */
else
DSC_INIT_IR(1, DSC_FALLING_EDGE, 0); /* detect falling edge */
IR_core_Philips((unsigned int) width);
trigger_edge = 1-trigger_edge;
#endif /* IR_PHILIPS */
}
#else
/* For the original style of IR handling */
#define _8259_EOI() (*(int *)0x14000600=0x20)
#define _8259_ICW (*(int *)0x14000600)
#define _8259_OCW (*(int *)0x14000604)
#ifdef IRQSHARE
#include "fsosd.h"
#include "irqshare.h"
#endif IRQSHARE
#ifdef CUST6
#include "config.h"
#endif
/************************************************************************
* Local variables. *
************************************************************************/
#ifdef IRQSHARE
PRIVATE unsigned int xor1value = 1;
#endif IRQSHARE
/* For IR receiving */
PRIVATE unsigned int prevIRtime = 0; /* Last time IR intr. happens */
PRIVATE unsigned short dataIR; /* System/customer IR code */
PRIVATE unsigned int diffIR[2]; /* Array to store time gap */
PRIVATE char cntIRchg = 0; /* Number of unprocessed IR intr*/
PRIVATE char cntIRbits = 0; /* Number of IR sys/cust. bits */
PRIVATE char killIR = 0; /* Whether to "kill" next IR bit*/
PRIVATE volatile char stateIR = IR_IDLE; /* IR state machine state */
#ifdef IR_SANYO
PRIVATE unsigned short IR_sanyo_codebar;/* Sanyo IR only */
#endif /* IR_SAYNO */
#ifdef IRREP
PRIVATE unsigned char previous_data; /* Record the previous id code */
#endif
/************************************************************************
* Local routines. *
************************************************************************/
PRIVATE void IR_core_NEC(int);
PRIVATE void IR_core_Philips(int);
/*
* Initialization. Properly set internal XOR's input value, then turn
* on interrupt.
*/
void IR_init()
{
#ifdef IRQSHARE
CLEAR_IRXOR;
/* SET_XOR1;
xor1value = 1;*/
CLEAR_XOR1;
xor1value = 0;
#else
#ifdef FLIP_IR
/*
* If incoming IR signal is flipped, then the first incoming edge
* will be a rising edge, so we need to clear the build-in
* XOR gate.
*/
CLEAR_IRXOR;
#else
SET_IRXOR; /* Set IR XOR to high at first */
#endif
#endif IRQSHARE
#ifdef IRXMT
if (!connect_inout) {
OUTIR_HIGH; /* IR output */
}
#endif
ASSIGN_SYSCODE; /* initialize sys code */
#ifdef IR_SANYO
IR_sanyo_codebar = (~sysIRcode) & 0x1fff;
#endif /* IR_SANYO */
#if defined(WEBDVD) && defined(SLAVE)
CLEAR_AUX0;
_8259_ICW = 0x16;
_8259_OCW = 0;
SET_AUX0;
#endif
mvd[riface_clear_dbgirq] = 0; /* Clear debug_irq */
enable_int(debug);
}
#if (IR_NEC || IR_SANYO)
PRIVATE void IR_core_NEC(falling_edge)
int falling_edge;
{
unsigned int *ir_tbl;
#define LEADER_LOW_MIN ir_tbl[0]
#define LEADER_LOW_MAX ir_tbl[1]
#define LEADER_HIGH_MIN ir_tbl[2]
#define LEADER_HIGH_MAX ir_tbl[3]
#define DATA_1_MIN ir_tbl[4]
#define DATA_1_MAX ir_tbl[5]
#define DATA_0_MIN ir_tbl[6]
#define DATA_0_MAX ir_tbl[7]
#ifdef IRREP
#define REPEAT_HIGH_MIN ir_tbl[8]
#define REPEAT_HIGH_MAX ir_tbl[9]
#define REPEAT_DATA_MIN ir_tbl[10]
#define REPEAT_DATA_MAX ir_tbl[11]
#endif
ir_tbl = T_IR_powerup_tbl;
#ifdef DSC
if (IS_POWER_DOWN) ir_tbl = T_IR_powerdn_tbl;
#endif
/* First IR interrupt should be a falling edge */
if (stateIR == IR_IDLE) {
if (falling_edge) stateIR = IR_LEADER_LOW;
else cntIRchg = prevIRtime = 0;
}
/*
* We only process things when we get 2 bits (i.e. 2 time period).
*/
if (cntIRchg == 2) {
unsigned char data;
char reset = 0;
unsigned int width;
cntIRchg = 0;
width = diffIR[1];
if (stateIR == IR_CUSTOM) {/* Put most common case first */
/*
* We are collecting system code or custom code
*/
width += diffIR[0]; /* Get data + gap */
dataIR <<= 1;
if ((width >= DATA_1_MIN) && (width <= DATA_1_MAX)) {
dataIR |= 0x1;
} else if ((width < DATA_0_MIN) || (width > DATA_1_MAX)) {
#ifdef IR_NEC
/*
* I am assert kill here because we may not recognize
* the singal because our checks are too tight; yet
* the external micro controller can still recognize it.
* By killing it, we guarantee that external logic won't
* recognize it.
*
* However, there may also be a downside: if IR input
* has noise, the external micro controll may still
* properly receive signal if we don't kill the input;
* if killIR is asserted, then this may be a problem.
*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -