| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2007 by Karl Kurbjun |
| * |
| * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| /* this file also handles the touch screen driver interface */ |
| |
| #include "config.h" |
| #include "cpu.h" |
| #include "system.h" |
| #include "button.h" |
| #include "kernel.h" |
| #include "backlight.h" |
| #include "adc.h" |
| #include "system.h" |
| #include "backlight-target.h" |
| #include "uart-target.h" |
| #include "tsc2100.h" |
| #include "string.h" |
| |
| #define BUTTON_TIMEOUT 50 |
| |
| #define BUTTON_START_BYTE 0xF0 |
| #define BUTTON_START_BYTE2 0xF4 /* not sure why, but sometimes you get F0 or F4, */ |
| /* but always the same one for the session? */ |
| static short last_x, last_y, last_z1, last_z2; /* for the touch screen */ |
| static bool touch_available = false; |
| |
| static enum touchpad_mode current_mode = TOUCHPAD_POINT; |
| static int touchpad_buttons[3][3] = { |
| {BUTTON_TOPLEFT, BUTTON_TOPMIDDLE, BUTTON_TOPRIGHT}, |
| {BUTTON_MIDLEFT, BUTTON_CENTER, BUTTON_MIDRIGHT}, |
| {BUTTON_BOTTOMLEFT, BUTTON_BOTTOMMIDDLE, BUTTON_BOTTOMRIGHT}, |
| }; |
| |
| void touchpad_set_mode(enum touchpad_mode mode) |
| { |
| current_mode = mode; |
| } |
| enum touchpad_mode touchpad_get_mode(void) |
| { |
| return current_mode; |
| } |
| |
| static struct touch_calibration_point topleft, bottomright; |
| |
| /* Jd's tests.. These will hopefully work for everyone so we dont have to |
| * create a calibration screen. |
| * Portait: |
| * (0,0) = 200, 3900 |
| * (480,640) = 3880, 270 |
| * Landscape: |
| * (0,0) = 200, 270 |
| * (640,480) = 3880, 3900 |
| */ |
| |
| static int touch_to_pixels(short val_x, short val_y) |
| { |
| short x,y; |
| |
| #if CONFIG_ORIENTATION == SCREEN_PORTRAIT |
| x=val_x; |
| y=val_y; |
| #else |
| x=val_y; |
| y=val_x; |
| #endif |
| |
| x = (x-topleft.val_x)*(bottomright.px_x - topleft.px_x) / (bottomright.val_x - topleft.val_x) + topleft.px_x; |
| y = (y-topleft.val_y)*(bottomright.px_y - topleft.px_y) / (bottomright.val_y - topleft.val_y) + topleft.px_y; |
| |
| if (x < 0) |
| x = 0; |
| else if (x>=LCD_WIDTH) |
| x=LCD_WIDTH-1; |
| |
| if (y < 0) |
| y = 0; |
| else if (y>=LCD_HEIGHT) |
| y=LCD_HEIGHT-1; |
| |
| |
| return (x<<16)|y; |
| } |
| |
| void button_init_device(void) |
| { |
| touch_available = false; |
| /* GIO is the power button, set as input */ |
| IO_GIO_DIR0 |= 0x01; |
| |
| #if CONFIG_ORIENTATION == SCREEN_PORTRAIT |
| topleft.val_x = 200; |
| topleft.val_y = 3900; |
| |
| bottomright.val_x = 3880; |
| bottomright.val_y = 270; |
| #else |
| topleft.val_x = 270; |
| topleft.val_y = 200; |
| |
| bottomright.val_x = 3900; |
| bottomright.val_y = 3880; |
| #endif |
| |
| topleft.px_x = 0; |
| topleft.px_y = 0; |
| |
| bottomright.px_x = LCD_WIDTH; |
| bottomright.px_y = LCD_HEIGHT; |
| |
| /* Enable the touchscreen interrupt */ |
| IO_INTC_EINT2 |= (1<<3); /* IRQ_GIO14 */ |
| #if 0 |
| tsc2100_writereg(TSADC_PAGE, TSADC_ADDRESS, |
| TSADC_PSTCM| |
| (0x2<<TSADC_ADSCM_SHIFT)| /* scan x,y,z1,z2 */ |
| (0x1<<TSADC_RESOL_SHIFT) /* 8 bit resolution */ |
| ); |
| /* doesnt work for some reason... |
| setting to 8bit would probably be better than the 12bit currently */ |
| #endif |
| } |
| |
| inline bool button_hold(void) |
| { |
| return false; |
| } |
| |
| static void remote_heartbeat(void) |
| { |
| char data[5] = {0x11, 0x30, 0x11^0x30, 0x11+0x30, '\0'}; |
| uart1_puts(data, 5); |
| } |
| |
| #define TOUCH_MARGIN 8 |
| char r_buffer[5]; |
| int r_button = BUTTON_NONE; |
| int button_read_device(int *data) |
| { |
| int retval, calbuf; |
| static int oldbutton = BUTTON_NONE; |
| |
| r_button=BUTTON_NONE; |
| *data = 0; |
| |
| if (touch_available) |
| { |
| short x,y; |
| static long last_touch = 0; |
| bool send_touch = false; |
| tsc2100_read_values(&x, &y, &last_z1, &last_z2); |
| if (TIME_BEFORE(last_touch + HZ/5, current_tick)) |
| { |
| if ((x > last_x + TOUCH_MARGIN) || |
| (x < last_x - TOUCH_MARGIN) || |
| (y > last_y + TOUCH_MARGIN) || |
| (y < last_y - TOUCH_MARGIN)) |
| { |
| send_touch = true; |
| } |
| } |
| else |
| send_touch = true; |
| if (send_touch) |
| { |
| last_x = x; |
| last_y = y; |
| *data = touch_to_pixels(x, y); |
| switch (current_mode) |
| { |
| case TOUCHPAD_POINT: |
| r_button |= BUTTON_TOUCHPAD; |
| break; |
| case TOUCHPAD_BUTTON: |
| { |
| int px_x = ((*data&0xffff0000)>>16), px_y = ((*data&0x0000ffff)); |
| r_button |= touchpad_buttons[px_y/(LCD_HEIGHT/3)][px_x/(LCD_WIDTH/3)]; |
| oldbutton = r_button; |
| break; |
| } |
| } |
| } |
| last_touch = current_tick; |
| touch_available = false; |
| } |
| remote_heartbeat(); |
| |
| if ((IO_GIO_BITSET0&0x01) == 0) |
| { |
| r_button |= BUTTON_POWER; |
| oldbutton=r_button; |
| } |
| |
| retval=uart1_gets_queue(r_buffer, 5); |
| do |
| { |
| for(calbuf=0;calbuf<4;calbuf++) |
| { |
| if((r_buffer[calbuf]&0xF0)==0xF0 && (r_buffer[calbuf+1]&0xF0)!=0xF0) |
| break; |
| } |
| calbuf++; |
| if(calbuf==5) |
| calbuf=0; |
| if(retval>=0) |
| { |
| r_button |= r_buffer[calbuf]; |
| oldbutton=r_button; |
| } |
| else |
| { |
| r_button=oldbutton; |
| } |
| } while((retval=uart1_gets_queue(r_buffer, 5))>=5); |
| |
| return r_button; |
| } |
| |
| /* Touchpad data available interupt */ |
| void read_battery_inputs(void); |
| void GIO14(void) |
| { |
| short tsadc = tsc2100_readreg(TSADC_PAGE, TSADC_ADDRESS); |
| short adscm = (tsadc&TSADC_ADSCM_MASK)>>TSADC_ADSCM_SHIFT; |
| switch (adscm) |
| { |
| case 1: |
| case 2: |
| touch_available = true; |
| break; |
| case 0xb: |
| read_battery_inputs(); |
| break; |
| } |
| //touch_available = true; |
| IO_INTC_IRQ2 = (1<<3); /* IRQ_GIO14 == 35 */ |
| } |