/*--- #ifndef RUN_IN_IRAM ---*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*--- #endif ---*/ /*--- #ifndef RUN_IN_IRAM ---*/ #include #include #include #include #include #define DIRECT_IR_GPIO_PIN CONFIG_INPUT_DIRECT_IR_GPIO struct _direct_ir { volatile unsigned int write; volatile unsigned int read; volatile signed int last_time; union __direct_ir_queue { struct _direct_ir_queue { unsigned int pol : 1; unsigned int timediv : 31; } value; unsigned int i; } Buffer[1024]; unsigned int time_sum; #ifndef RUN_IN_IRAM struct timer_list timer; struct input_dev *in_dev; #endif /*--- #ifndef RUN_IN_IRAM ---*/ int ledhandle; }; #ifndef RUN_IN_IRAM static void direct_wq_function(unsigned long data); static void direct_ir_control_led(void); #endif /*--- #ifndef RUN_IN_IRAM ---*/ struct _direct_ir D_IR; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ enum _rc6_symbol { rc6_symbol_non, rc6_symbol_leader, /* 8T */ rc6_symbol_one, /* 2T */ rc6_symbol_zero, /* 2T */ rc6_symbol_trailer_one, /* 4T */ rc6_symbol_trailer_zero, /* 4T */ rc6_symbol_end }; #ifndef RUN_IN_IRAM char *_rc6_symbol_name[] = { "rc6_symbol_non", "rc6_symbol_leader", /* 8T */ "rc6_symbol_one", /* 2T */ "rc6_symbol_zero", /* 2T */ "rc6_symbol_trailer_one", /* 4T */ "rc6_symbol_trailer_zero", "rc6_symbol_end" }; #endif /*--- #ifndef RUN_IN_IRAM ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ enum _rc6_symbol direct_make_rc6_symbol(unsigned int pegel, unsigned int time) { static unsigned high_time = 0; static unsigned low_time = 0; /*--- printk("[direct_make_rc6_symbol] pegel = %u time = %u\n", pegel, time); ---*/ if(time == 0) { high_time = 0; low_time = 0; return rc6_symbol_non; } if(pegel == 0) { /* low */ low_time += time; /*--- printk("[direct_make_rc6_symbol] low_time %u high_time %u\n", low_time, high_time); ---*/ if((high_time == 6) && (low_time == 2)) { high_time = low_time = 0; return rc6_symbol_leader; } if((high_time == 1) && (low_time >= 1)) { high_time = 0; low_time -= 1; return rc6_symbol_one; } if((high_time == 2) && (low_time >= 2)) { high_time = 0; low_time -= 2; return rc6_symbol_trailer_one; } return rc6_symbol_non; } high_time += time; /*--- printk("[direct_make_rc6_symbol] low_time %u high_time %u\n", low_time, high_time); ---*/ if((high_time >= 1) && (low_time == 1)) { high_time -= 1; low_time = 0; return rc6_symbol_zero; } if((high_time >= 2) && (low_time == 2)) { high_time -= 2; low_time = 0; return rc6_symbol_trailer_zero; } return rc6_symbol_non; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #ifndef RUN_IN_IRAM static inline void input_report_misc(struct input_dev *dev,unsigned int code,int value) { input_event(dev, EV_MSC, code, value); } #endif /*--- #ifndef RUN_IN_IRAM ---*/ unsigned int direct_ir_waited = 0; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void direct_wq_function(unsigned long data) { enum _rc6_symbol symbol, last_symbol = rc6_symbol_non; static unsigned int rc6_header, rc6_info, *info = &rc6_header; direct_ir_waited++; while((D_IR.write != D_IR.read) || (direct_ir_waited == 1)) { union __direct_ir_queue V; unsigned int u_sec, t; /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ int process_symbol(void) { D_IR.time_sum += u_sec; symbol = direct_make_rc6_symbol(V.value.pol ? 0 : 1, t); /*--- printk("decode: %s header 0x%x info 0x%x\n", _rc6_symbol_name[symbol], rc6_header, rc6_info); ---*/ if(symbol == rc6_symbol_non) return 1; switch(symbol) { case rc6_symbol_leader: if(rc6_header && rc6_info) { printk("[end:0x%x:0x%x]\n", rc6_header, rc6_info); if(((rc6_info >> 16) & 0xFFFF) != 0x803B) { printk("WARNING: nicht AVM !\n"); } else { printk("[IR] 0x%x\n", rc6_info & 0xFFFF); #ifndef RUN_IN_IRAM direct_ir_control_led(); input_report_misc(D_IR.in_dev, MSC_RAW, rc6_info & 0xFFFF); input_sync(D_IR.in_dev); davinci_key_to_power_control(rc6_info & 0xFFFF); #endif /*--- #ifndef RUN_IN_IRAM ---*/ } } printk("[header:0x%x:0x%x:%s]", rc6_header, rc6_info, _rc6_symbol_name[last_symbol]); rc6_header = 0, rc6_info = 0; info = &rc6_header; break; case rc6_symbol_one: *info <<= 1; *info |= 1; break; case rc6_symbol_zero: *info <<= 1; *info |= 0; break; case rc6_symbol_trailer_one: case rc6_symbol_trailer_zero: printk("[trailer:0x%x:0x%x:%u]", rc6_header, rc6_info, t); info = &rc6_info; break; case rc6_symbol_end: break; } last_symbol = symbol; /*--- printk("decode: %s header 0x%x info 0x%x\n", _rc6_symbol_name[symbol], rc6_header, rc6_info); ---*/ return 0; } /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ if(D_IR.write != D_IR.read) { V.i = D_IR.Buffer[D_IR.read++].i; if (D_IR.read >= sizeof(D_IR.Buffer) / sizeof(D_IR.Buffer[0])) D_IR.read = 0; direct_ir_waited = 0; } else if(direct_ir_waited == 1) { #ifndef RUN_IN_IRAM signed int davinci_get_check_idle_timer(void); signed int time = davinci_get_check_idle_timer(); #else /*--- #ifndef RUN_IN_IRAM ---*/ signed int time; #endif /*--- #else ---*/ /*--- #ifndef RUN_IN_IRAM ---*/ V.value.timediv = (time - D_IR.last_time) >> 0; if(V.value.timediv > 10 * 44 * 67) V.value.timediv = 10 * 44 * 67; V.value.pol = 1; /* virtuelle Flanke nach high */ direct_ir_waited++; /*--- printk("Last\n"); ---*/ } u_sec = ((V.value.timediv * 10) + 67/2) / (67); if(u_sec > 40000) { if(rc6_info && rc6_header) { if(V.value.timediv > 10 * 44 * 67) V.value.timediv = 10 * 44 * 67; V.value.pol = 1; /* virtuelle Flanke nach high */ direct_ir_waited = 2; process_symbol(); } D_IR.time_sum = 0; u_sec = 0; } t = (u_sec + 222) / 444; printk("[%u/%u]", t, V.value.pol ? 0 : 1); #if 0 printk("[%5u] %s %u us => t %u\n", D_IR.time_sum, V.value.pol ? "UP " : "DOWN", u_sec, t ); #endif if(process_symbol()) continue; } if(direct_ir_waited == 2 && rc6_info) { #if 0 printk("Result: LB %u SB %u M %u\n", (rc6_header >> 4) & 0x1, (rc6_header >> 3) & 0x1, (rc6_header >> 0) & 0x7); printk("Result: scc 0x%x info 0x%x\n", (rc6_info >> 16) & 0xFFFF, (rc6_info >> 0) & 0xFFFF); #endif printk("[end:0x%x:0x%x]", rc6_header, rc6_info); if(((rc6_info >> 16) & 0xFFFF) != 0x803B) { printk("WARNING: nicht AVM !\n"); } else { printk("[IR] 0x%x\n", rc6_info & 0xFFFF); #ifndef RUN_IN_IRAM direct_ir_control_led(); input_report_misc(D_IR.in_dev, MSC_RAW, rc6_info & 0xFFFF); input_sync(D_IR.in_dev); davinci_key_to_power_control(rc6_info & 0xFFFF); #endif /*--- #ifndef RUN_IN_IRAM ---*/ } rc6_info = 0; } #ifndef RUN_IN_IRAM del_timer(&D_IR.timer); D_IR.timer.expires = jiffies + HZ / 10; add_timer(&D_IR.timer); #endif /*--- #ifndef RUN_IN_IRAM ---*/ } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #ifndef RUN_IN_IRAM irqreturn_t direct_ir_isr(int irq, void *context) { return IRQ_NONE; } #endif /*--- #ifndef RUN_IN_IRAM ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void direct_ir_firq(void) __attribute__ ((interrupt)); void direct_ir_firq(void) { struct gpio_controller *GPIO = (struct gpio_controller *)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10); struct irq_controller *IRQ = (struct irq_controller *)IO_ADDRESS(DAVINCI_ARM_INTC_BASE); /*--- printk("[direct_ir_isr]\n"); ---*/ if(GPIO->intstat & (1 << DIRECT_IR_GPIO_PIN)) { #ifndef RUN_IN_IRAM signed int davinci_get_check_idle_timer(void); signed int time = davinci_get_check_idle_timer(); #else /*--- #ifndef RUN_IN_IRAM ---*/ signed int time; #endif /*--- #else ---*/ /*--- #ifndef RUN_IN_IRAM ---*/ union __direct_ir_queue V; GPIO->intstat |= (1 << DIRECT_IR_GPIO_PIN); #if (IRQ_GPIO0 + DIRECT_IR_GPIO_PIN) < 32 IRQ->FIQ0 = 1 << (IRQ_GPIO0 + DIRECT_IR_GPIO_PIN); #else /*--- #if (IRQ_GPIO0 + DIRECT_IR_GPIO_PIN) < 32 ---*/ IRQ->FIQ1 = 1 << (IRQ_GPIO0 + DIRECT_IR_GPIO_PIN - 32); #endif /*--- #else ---*/ /*--- #if (IRQ_GPIO0 + DIRECT_IR_GPIO_PIN) < 32 ---*/ V.value.pol = (GPIO->in_data & (1 << DIRECT_IR_GPIO_PIN)) ? 1 : 0; V.value.timediv = (time - D_IR.last_time) >> 0; D_IR.last_time = time; D_IR.Buffer[D_IR.write++].i = V.i; if (D_IR.write >= sizeof(D_IR.Buffer) / sizeof(D_IR.Buffer[0])) D_IR.write = 0; } return; } #if 0 /*--- void direct_ir_firq(void) __attribute__ ((noreturn, pure, used, interrupt)) { ---*/ void direct_ir_firq(void) __attribute__ ((used, interrupt)); void direct_ir_firq(void) { struct gpio_controller *GPIO = (struct gpio_controller *)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10); struct timer *TIMER = (struct timer *)IO_ADDRESS(DAVINCI_TIMER1_BASE); if(GPIO->intstat & (1 << DIRECT_IR_GPIO_PIN)) { signed int time = TIMER->tim12; union __direct_ir_queue V; GPIO->intstat |= (1 << DIRECT_IR_GPIO_PIN); V.value.pol = (GPIO->in_data & (1 << DIRECT_IR_GPIO_PIN)) ? 1 : 0; V.value.timediv = (time - D_IR.last_time) >> 0; D_IR.last_time = time; D_IR.Buffer[D_IR.write++].i = V.i; if (D_IR.write >= sizeof(D_IR.Buffer) / sizeof(D_IR.Buffer[0])) D_IR.write = 0; } } #endif /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ char firq_stack[0x1000]; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #ifndef RUN_IN_IRAM static void direct_ir_led_remove(int handle) { printk("[cbremove:%d]\n",handle); if(handle == D_IR.ledhandle ) { D_IR.ledhandle = 0; } } #endif /*--- #ifndef RUN_IN_IRAM ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #ifndef RUN_IN_IRAM void direct_ir_control_led(void) { if(D_IR.ledhandle == 0) { D_IR.ledhandle = avm_led_alloc_handle("info", 0, direct_ir_led_remove); if((D_IR.ledhandle & 0xFFFFFF00) == 0xFFFFFF00) { D_IR.ledhandle = 0; } printk("ledhandle:%x\n", D_IR.ledhandle); } if(D_IR.ledhandle) avm_led_action_with_handle(D_IR.ledhandle, avm_led_flash_on_125ms); } #endif /*--- #ifndef RUN_IN_IRAM ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #ifndef RUN_IN_IRAM static int direct_ir_led_RegisterInputDevice(void) { int err=0; printk("[ir_init]\n"); D_IR.in_dev = input_allocate_device(); if( !D_IR.in_dev ) { printk(KERN_ERR "msp430.c: Can't allocate input device\n"); return -ENOMEM; } D_IR.in_dev->name = "MSP430_IR"; D_IR.in_dev->id.bustype = BUS_PCI; D_IR.in_dev->id.vendor = PCI_VENDOR_ID_AVM; D_IR.in_dev->id.product = 0x0000; D_IR.in_dev->id.version = 0x0100; D_IR.in_dev->evbit[0] = BIT(EV_MSC); // | BIT(EV_REP); //D_IR.in_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); D_IR.in_dev->mscbit[LONG(MSC_RAW)] = BIT(MSC_RAW); input_register_device(D_IR.in_dev); return 0; } #endif /*--- #ifndef RUN_IN_IRAM ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static struct resource my_irq_gpio_resource = { .name = "direct IR", .flags = IORESOURCE_IO }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int __init direct_ir_init(void) { struct gpio_controller *GPIO = (struct gpio_controller *)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10); volatile unsigned int *gpio_bank_irq_enable = (volatile unsigned int *)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x08); #ifndef RUN_IN_IRAM int ret; printk("[direct_ir_init]\n"); if(davinci_revision[1] == 0) { printk("[direct_ir_init] no direct IR on old Hardware\n"); return 0; } my_irq_gpio_resource.start = my_irq_gpio_resource.end = GPIO_INPUT_PIN; if(request_resource(&gpio_resource, &my_irq_gpio_resource)) { printk(KERN_ERR "ERROR: gpio %u is not avalible as irq pin\n", GPIO_INPUT_PIN); return -EFAULT; } printk("[direct_ir_init]\n"); /*--- board_setup_gpio("direct_ir", DIRECT_IR_GPIO_PIN); ---*/ davinci_gpio_ctrl(DIRECT_IR_GPIO_PIN, GPIO_PIN, GPIO_INPUT_PIN); GPIO->set_rising = 1 << DIRECT_IR_GPIO_PIN; GPIO->set_falling = 1 << DIRECT_IR_GPIO_PIN; printk("GPIO->set_rising 0x%x GPIO->set_falling 0x%x\n", GPIO->set_rising, GPIO->set_falling); *gpio_bank_irq_enable |= 1; GPIO->intstat = (1 << DIRECT_IR_GPIO_PIN); /* clear pending irqs */ printk("GPIO->intstat = 0x%x gpio_bank_irq_enable = 0x%x \n", GPIO->intstat, *gpio_bank_irq_enable); #endif /*--- #ifndef RUN_IN_IRAM ---*/ { /*----------------------------------------------------------------------------------*\ 100: e59ff000 ldr pc, [pc, #0] ; 108 <.text+0x108> 104: 00000000 .word 0x00000000 \*----------------------------------------------------------------------------------*/ extern void vector_fiq(void); unsigned int *firq_vector = (unsigned int *)0xffff0400; firq_vector[0] = 0xe59fd000; /*--- ldr sp, [pc, #0x00] ---*/ firq_vector[1] = 0xe59ff000; /*--- ldr pc, [pc, #0x00] ---*/ firq_vector[2] = (unsigned int)firq_stack + 0xFFC; firq_vector[3] = (unsigned int)direct_ir_firq; flush_icache_range(0xffff0400, 0xffff0400 + 4 * 4); } #ifndef RUN_IN_IRAM ret = request_irq(IRQ_GPIO0 + DIRECT_IR_GPIO_PIN, direct_ir_isr, SA_INTERRUPT, "direct_ir", &D_IR); if(ret) { return ret; } #endif /*--- #ifndef RUN_IN_IRAM ---*/ GPIO->intstat |= (1 << DIRECT_IR_GPIO_PIN); /* clear pending irqs */ #ifndef RUN_IN_IRAM printk("GPIO->intstat = 0x%x gpio_bank_irq_enable = 0x%x \n", GPIO->intstat, *gpio_bank_irq_enable); direct_ir_led_RegisterInputDevice(); setup_timer(&(D_IR.timer), direct_wq_function, 0); D_IR.timer.expires = jiffies + HZ / 10; add_timer(&D_IR.timer); printk("[direct_ir_init] success\n"); #endif /*--- #ifndef RUN_IN_IRAM ---*/ return 0; } #ifndef RUN_IN_IRAM late_initcall(direct_ir_init); #endif /*--- #ifndef RUN_IN_IRAM ---*/