123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- /*
- * linux/drivers/input/irremote/sw_remote_kbd.c
- *
- * Keypad Driver
- *
- * Copyright (C) 2009 Amlogic Corporation
- *
- *
- * 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
- * author : jianfeng_wang
- */
- /*
- * !!caution: if you use remote ,you should disable card1 used for ata_enable pin.
- */
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/types.h>
- #include <linux/input.h>
- #include <linux/kernel.h>
- #include <linux/delay.h>
- #include <linux/platform_device.h>
- #include <linux/mutex.h>
- #include <linux/errno.h>
- #include <asm/irq.h>
- #include <asm/io.h>
- #include <mach/am_regs.h>
- #include "am_remote.h"
- extern char *remote_log_buf;
- static int dbg_printk(const char *fmt, ...)
- {
- char buf[100];
- va_list args;
- va_start(args, fmt);
- vscnprintf(buf, 100, fmt, args);
- if (strlen(remote_log_buf) + (strlen(buf) + 64) > REMOTE_LOG_BUF_LEN) {
- remote_log_buf[0] = '\0';
- }
- strcat(remote_log_buf, buf);
- va_end(args);
- return 0;
- }
- static int get_pulse_width(unsigned long data)
- {
- struct remote *remote_data = (struct remote *)data;
- int pulse_width;
- const char *state;
- pulse_width = (am_remote_read_reg(AM_IR_DEC_REG1) & 0x1FFF0000) >> 16;
- state = remote_data->step == REMOTE_STATUS_WAIT ? "wait" :
- remote_data->step == REMOTE_STATUS_LEADER ? "leader" :
- remote_data->step == REMOTE_STATUS_DATA ? "data" :
- remote_data->step == REMOTE_STATUS_SYNC ? "sync" : NULL;
- dbg_printk("%02d:pulse_wdith:%d==>%s\r\n",
- remote_data->bit_count - remote_data->bit_num, pulse_width, state);
- //sometimes we found remote pulse width==0. in order to sync machine state we modify it .
- if (pulse_width == 0) {
- switch (remote_data->step) {
- case REMOTE_STATUS_LEADER:
- pulse_width = remote_data->time_window[0] + 1;
- break;
- case REMOTE_STATUS_DATA:
- pulse_width = remote_data->time_window[2] + 1;
- break;
- }
- }
- return pulse_width;
- }
- static inline void kbd_software_mode_remote_wait(unsigned long data)
- {
- unsigned short pulse_width;
- struct remote *remote_data = (struct remote *)data;
- pulse_width = get_pulse_width(data);
- remote_data->step = REMOTE_STATUS_LEADER;
- remote_data->cur_keycode = 0;
- remote_data->bit_num = remote_data->bit_count;
- }
- static inline void kbd_software_mode_remote_leader(unsigned long data)
- {
- unsigned short pulse_width;
- struct remote *remote_data = (struct remote *)data;
- pulse_width = get_pulse_width(data);
- if ((pulse_width > remote_data->time_window[0])
- && (pulse_width < remote_data->time_window[1])) {
- remote_data->step = REMOTE_STATUS_DATA;
- } else {
- remote_data->step = REMOTE_STATUS_WAIT;
- }
- remote_data->cur_keycode = 0;
- remote_data->bit_num = remote_data->bit_count;
- }
- static inline void kbd_software_mode_remote_send_key(unsigned long data)
- {
- struct remote *remote_data = (struct remote *)data;
- unsigned int reort_key_code = remote_data->cur_keycode >> 16 & 0xffff;
- remote_data->step = REMOTE_STATUS_SYNC;
- if (remote_data->repeate_flag) {
- if (remote_data->custom_code != (remote_data->cur_keycode & 0xffff)) {
- return;
- }
- if (((reort_key_code & 0xff) ^ (reort_key_code >> 8 & 0xff)) !=
- 0xff) {
- return;
- }
- if (remote_data->repeat_tick < jiffies) {
- remote_send_key(remote_data->input,
- (remote_data->cur_keycode >> 16) & 0xff, 2);
- remote_data->repeat_tick +=
- msecs_to_jiffies(remote_data->input->rep[REP_PERIOD]);
- }
- } else {
- switch (remote_data->work_mode) {
- case REMOTE_WORK_MODE_FIQ_RCMM:
- if (remote_data->custom_code !=
- (remote_data->cur_keycode & 0xfff)) {
- input_dbg("Wrong custom code is 0x%08x\n",
- remote_data->cur_keycode);
- return;
- }
- if (remote_data->bit_count == 32)
- remote_send_key(remote_data->input,
- 0x100 | (remote_data->cur_keycode >>
- (remote_data->bit_count - 8)),
- 1);
- else
- remote_send_key(remote_data->input,
- remote_data->
- cur_keycode >> (remote_data->bit_count -
- 8), 1);
- break;
- default:
- if (remote_data->custom_code !=
- (remote_data->cur_keycode & 0xffff)) {
- input_dbg("Wrong custom code is 0x%08x\n",
- remote_data->cur_keycode);
- return;
- }
- if (((reort_key_code & 0xff) ^
- (reort_key_code >> 8 & 0xff)) == 0xff)
- remote_send_key(remote_data->input,
- (remote_data->cur_keycode >> 16) & 0xff,
- 1);
- }
- if (remote_data->repeat_enable)
- remote_data->repeat_tick =
- jiffies +
- msecs_to_jiffies(remote_data->input->rep[REP_DELAY]);
- }
- }
- static inline void kbd_software_mode_remote_data(unsigned long data)
- {
- unsigned short pulse_width;
- struct remote *remote_data = (struct remote *)data;
- pulse_width = get_pulse_width(data);
- remote_data->step = REMOTE_STATUS_DATA;
- switch (remote_data->work_mode) {
- case REMOTE_WORK_MODE_SW:
- case REMOTE_WORK_MODE_FIQ:
- if ((pulse_width > remote_data->time_window[2])
- && (pulse_width < remote_data->time_window[3])) {
- remote_data->bit_num--;
- } else if ((pulse_width > remote_data->time_window[4])
- && (pulse_width < remote_data->time_window[5])) {
- remote_data->cur_keycode |=
- 1 << (remote_data->bit_count - remote_data->bit_num);
- remote_data->bit_num--;
- } else {
- remote_data->step = REMOTE_STATUS_WAIT;
- }
- if (remote_data->bit_num == 0) {
- remote_data->repeate_flag = 0;
- remote_data->send_data = 1;
- if (remote_data->work_mode == REMOTE_WORK_MODE_FIQ)
- fiq_bridge_pulse_trigger
- (&remote_data->fiq_handle_item);
- else {
- remote_bridge_isr(0, remote_data);
- }
- }
- break;
- case REMOTE_WORK_MODE_FIQ_RCMM:
- if ((pulse_width > remote_data->time_window[2])
- && (pulse_width < remote_data->time_window[3])) {
- if ((remote_data->bit_num == 12) && (remote_data->bit_count == 24)) { /*sub mode is remote control */
- remote_data->bit_count += 8;
- remote_data->bit_num += 8;
- }
- remote_data->bit_num -= 2;
- } else if ((pulse_width > remote_data->time_window[4])
- && (pulse_width < remote_data->time_window[5])) {
- remote_data->cur_keycode |=
- 1 << (remote_data->bit_count - remote_data->bit_num);
- remote_data->bit_num -= 2;
- } else if ((pulse_width > remote_data->time_window[8])
- && (pulse_width < remote_data->time_window[9])) {
- remote_data->cur_keycode |=
- 2 << (remote_data->bit_count - remote_data->bit_num);
- if ((remote_data->bit_num == 20) && (remote_data->bit_count == 32)) { /*sub mode is keyboard */
- remote_data->bit_count -= 8;
- remote_data->bit_num -= 8;
- }
- remote_data->bit_num -= 2;
- } else if ((pulse_width > remote_data->time_window[10])
- && (pulse_width < remote_data->time_window[11])) {
- remote_data->cur_keycode |=
- 3 << (remote_data->bit_count - remote_data->bit_num);
- remote_data->bit_num -= 2;
- } else {
- remote_data->step = REMOTE_STATUS_WAIT;
- }
- if (remote_data->bit_num == 0) {
- remote_data->repeate_flag = 0;
- remote_data->send_data = 1;
- fiq_bridge_pulse_trigger(&remote_data->fiq_handle_item);
- }
- break;
- }
- }
- static inline void kbd_software_mode_remote_sync(unsigned long data)
- {
- unsigned short pulse_width;
- struct remote *remote_data = (struct remote *)data;
- pulse_width = get_pulse_width(data);
- if ((pulse_width > remote_data->time_window[6])
- && (pulse_width < remote_data->time_window[7])) {
- remote_data->repeate_flag = 1;
- if (remote_data->repeat_enable) {
- remote_data->send_data = 1;
- } else {
- remote_data->step = REMOTE_STATUS_SYNC;
- return;
- }
- }
- remote_data->step = REMOTE_STATUS_SYNC;
- if ((remote_data->work_mode == REMOTE_WORK_MODE_FIQ)
- || (remote_data->work_mode == REMOTE_WORK_MODE_FIQ_RCMM)) {
- fiq_bridge_pulse_trigger(&remote_data->fiq_handle_item);
- } else {
- remote_bridge_isr(0, remote_data);
- }
- }
- void remote_sw_reprot_key(unsigned long data)
- {
- struct remote *remote_data = (struct remote *)data;
- int current_jiffies = jiffies;
- if (((current_jiffies - remote_data->last_jiffies) > 20)
- && (remote_data->step <= REMOTE_STATUS_SYNC)) {
- remote_data->step = REMOTE_STATUS_WAIT;
- }
- remote_data->last_jiffies = current_jiffies; //ignore a little msecs
- switch (remote_data->step) {
- case REMOTE_STATUS_WAIT:
- kbd_software_mode_remote_wait(data);
- break;
- case REMOTE_STATUS_LEADER:
- kbd_software_mode_remote_leader(data);
- break;
- case REMOTE_STATUS_DATA:
- kbd_software_mode_remote_data(data);
- break;
- case REMOTE_STATUS_SYNC:
- kbd_software_mode_remote_sync(data);
- break;
- default:
- break;
- }
- }
- irqreturn_t remote_bridge_isr(int irq, void *dev_id)
- {
- struct remote *remote_data = (struct remote *)dev_id;
- if (remote_data->send_data) { //report key
- kbd_software_mode_remote_send_key((unsigned long)remote_data);
- remote_data->send_data = 0;
- }
- remote_data->timer.data = (unsigned long)remote_data;
- mod_timer(&remote_data->timer,
- jiffies + msecs_to_jiffies(remote_data->release_delay));
- return IRQ_HANDLED;
- }
|