📄 gamectrl.c
字号:
* routine is called mostly inside timer interrupt handler. Originally,
* we have a semaphore to prevent calling this while communicating
* with 3207. The new mechanism will disable any interrupt while
* communicating with 3207, so semaphore is no longer needed.
*/
void DSC_toggle()
{
DSC_DESELECT;
DSC_SELECT;
}
/*
* Send DSC command from 3208/3210 to 3207
* dcs_c: CS1
* dsc_s: AUX3
* d[7:0]: data[7:0]
* DSC data space is at address 0x14000003 (i.e. assert CS1)
*/
unsigned int DSC_cmd(unsigned int addr, unsigned int data)
{
volatile unsigned char* prt;
/*
* Disable interrupt while communicating with 3207 such address
* and data can always be in pair.
*/
mvd[riface_irqsuppress] = 0;
asm("nop");
prt = (char *) x14000003;
/* asserting dsc strobe from 3210 */
*prt = addr;
asm("nop"); asm("nop");
if (!(addr & 0x1)) {
*prt = data;
data = 0;
} else data = *prt;
return(data);
}
/*
* Fuction to set and/or clear AUX pins on 3205/3207/3209.
*
* Inputs:
* sel: 0 - for dsc_aux0
* 1 - for dsc_aux1
* set: 0 - clear according to mask
* 1 - set according to mask
* 2 - tristate pads specified by mask
* mask: mask to be used
*/
void DSC_set_aux(sel, set, mask)
int sel, set, mask;
{
register psw_shadow, temp;
volatile char *ptr;
int data, ctl, *pdat, *pctl;
asm volatile("movfrs psw,%0": "=r" (psw_shadow) );
/* Non-cachable bank1 address (CS1) */
ptr = (char *) x14000003;
/* Decide which 3207 register to use (dsc_aux0 vs. dsc_aux1) */
if (sel) {
pdat = &shadow_eaux1_dat;
pctl = &shadow_eaux1_ctl;
data = dsc_aux1_data;
ctl = dsc_aux1_ctl;
} else {
pdat = &shadow_eaux0_dat;
pctl = &shadow_eaux0_ctl;
data = dsc_aux0_data;
ctl = dsc_aux0_ctl;
}
/* Disable interrupt so everything can happen together */
temp = 0x1fd5;
asm volatile("movtos %0,psw" : :"r" (temp));
asm("nop");
asm("nop");
/* Set the PAD value first (keep a copy in shadow) */
*ptr = data;
/* When setting or tri-stating, OR in the mask */
if (set) *ptr = (*pdat |= mask);
else *ptr = (*pdat &= ~mask);
/* Set the enable bit (unless it is tri-state) */
asm("nop");
*ptr = ctl;
/* When tri-stating, turn the bit off */
if (set == 2) *ptr = (*pctl &= ~mask);
else *ptr = (*pctl |= mask);
/* Restore PSD */
asm volatile("movtos %0,psw" : :"r" (psw_shadow));
}
PRIVATE int la_trigger; /* For logic analyzer */
/*
* This routine will be called inside interrupt handler. With 3207, we'll
* be reset by 3207; without 3207, we'll just jump to start up code.
*/
void DSC_dead(trigger)
int trigger;
{
/* Sit here and wait for 3207 to reset us. */
while (1) la_trigger = trigger;
}
#ifdef DSC_IRQ
/*
* This routine updates dsc_aux_mode and dsc_irq_ctl registers.
*
* Inputs:
* on: 0: turning off
* 1: turning on
* edge: 0: trigger on rising edge
* 1: trigger on falling edge
* setmode:0: Don't touch dsc_aux_mode and IRQOUT. They are right (only
* used for change IR trigger edge for Philips IR.)
* 1: Drive IRQOUT high and set dsc_aux_mode (normal case)
* mask: interrupt mask;
* falling:patter to enable triggering on falling edge
*/
PRIVATE void DSC_init_irq_ctl(on, edge, setmode, mask, falling)
int on, edge, setmode, mask, falling;
{
int mode, ctl;
mode = shadow_aux_mode;
ctl = shadow_irq_ctl;
/* Set irq_ctl register */
ctl &= ~mask; /* Clear the mask first */
if (on) {
ctl |= mask; /* Enable the interrupt */
ctl &= ~falling; /* Assume trigger on rising edge*/
if (edge == DSC_FALLING_EDGE)
ctl |= falling;
}
if (setmode) {
/* Set aux_mode register */
mode &= ~2; /* Clear SQCK */
/* If S0S1 is enabled, then enable SQCK */
if (ctl & 2) mode |= 2;
/* If no interrupt mask is on, then disable interrupt output */
mode &= ~1;
if (ctl & 0xf) {
mode |= 1;
CLEAR_IRQOUT; /* Drive EAUX11 low */
CLEAR_IRXOR; /* EAUX11 is active high */
}
/*
* The only time setmode is not set is when changing the
* IR triggering edge for Philips IR. In which case, there
* is no need to change mode.
*/
shadow_aux_mode = mode;
DSC_cmd(dsc_aux_mode, shadow_aux_mode);
}
/*
* Need to protect because we may change IR's edge in IR handler.
* Thus, it is possible that interrupt hits after shadow_irq_ctl
* but before dsc_irq_ctl is really updated.
*
* riface_irqsuppress should be good enought because we do
* riface_irqsuppress inside DSC_cmd;
*/
mvd[riface_irqsuppress] = 0;
asm("nop");
shadow_irq_ctl = ctl;
DSC_cmd(dsc_irq_ctl, shadow_irq_ctl);
}
/*
* Turn ON or OFF IR handling by 3881
* Inputs:
* on: 0: turn off
* 1: turn on
* edge: 0: rising
* 1: falling
* setmode:0: Don't set dsc_aux_mode (assume it is set right already)
* 1: Set dsc_aux_mode as well as pull IRQOUT high (normal case)
*/
void DSC_init_ir(on, edge, setmode)
int on, edge, setmode;
{
TRISTATE_IRIN; /* Allow IR to come in on EAUX15 */
DSC_init_irq_ctl(on, edge, setmode, 1, 0x10);
}
#endif /* DSC_IRQ */
/************************************************************************/
/************** This part is from version 1.56 of ir.c *******************/
/************************************************************************/
#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
/* Timer values when CPU is running at full speed */
unsigned int IR_powerup_tbl[] = {
#ifdef DSC_IRQ
/* Use 3881's internal counter to keep track of time */
#ifdef IR_PHILIPS
/* For Philips format */
3,
8,
9,
16,
#else
/* For NEC and SANYO formats */
85, /* Leader low+high min (12.89ms)*/
93, /* Leader low+high max (14.10ms)*/
12, /* Gap+data 1 minimum (1.82ms) */
19, /* Gap+data 1 maximum (2.88ms) */
4, /* Gap+data 0 minimum (0.61ms) */
11, /* Gap+data 0 maximum (1.67ms) */
#ifdef IRREP
70, /* Rep low+high min (10.62ms) */
78, /* Rep low+high max (11.83ms) */
#endif /* IRREP */
#endif /* else of IR_PHILIPS */
#else
/* Use CPU's timer2 to keep track of time */
#ifdef IR_PHILIPS
/* For Philips format */
CPUCLK * 50, /* minimum length of half bit */
CPUCLK * 130, /* maximum length of half bit */
CPUCLK * 140, /* minimum length of one bit */
CPUCLK * 240, /* maximum length of one bit */
#else
/* For NEC and SANYO formats */
CPUCLK * 880, /* Leader low minimum */
CPUCLK * 920, /* Leader low maximum */
CPUCLK * 430, /* Leader high minimum */
CPUCLK * 470, /* Leader high maximum */
CPUCLK * 205, /* Data 1 minimum */
CPUCLK * 245, /* Data 1 maximum */
CPUCLK * 92, /* Data 0 minimum */
CPUCLK * 132, /* Data 0 maximum */
#ifdef IRREP
CPUCLK * 205, /* Repeat high minimun */
CPUCLK * 245, /* Repeat high mazimun */
CPUCLK * 36, /* Repeat data minimum */
CPUCLK * 76 /* Repeat data maxmun */
#endif /* IRREP */
#endif /* else of IR_PHILIPS */
#endif /* else of DSC_IRQ */
};
#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 = 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -