Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
132 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
427 farthen 6
//    This file is part of emCORE.
132 theseven 7
//
427 farthen 8
//    emCORE is free software: you can redistribute it and/or
132 theseven 9
//    modify it under the terms of the GNU General Public License as
10
//    published by the Free Software Foundation, either version 2 of the
11
//    License, or (at your option) any later version.
12
//
427 farthen 13
//    emCORE is distributed in the hope that it will be useful,
132 theseven 14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
//    See the GNU General Public License for more details.
17
//
18
//    You should have received a copy of the GNU General Public License along
427 farthen 19
//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
132 theseven 20
//
21
//
22
 
23
 
24
#include "global.h"
25
#include "clickwheel.h"
26
#include "button.h"
27
#include "thread.h"
28
#include "timer.h"
29
#include "s5l8701.h"
30
#include "contextswitch.h"
31
 
32
 
33
static struct wakeup clickwheel_wakeup IBSS_ATTR;
968 theseven 34
static struct wakeup clickwheel_init_wakeup INITDATA_ATTR;
132 theseven 35
static volatile uint32_t clickwheel_packet IBSS_ATTR;
429 theseven 36
static struct scheduler_thread clickwheel_thread_handle;
37
static uint32_t clickwheel_stack[0x100] STACK_ATTR;
968 theseven 38
static bool wheel_initialized IBSS_ATTR;
132 theseven 39
static bool oldtouched IBSS_ATTR;
40
static int oldpos IBSS_ATTR;
41
static int oldbuttons IBSS_ATTR;
968 theseven 42
static int lastpacket IBSS_ATTR;
132 theseven 43
static int packets IBSS_ATTR;
138 theseven 44
static int collect IBSS_ATTR;
45
static int lastdiff IBSS_ATTR;
132 theseven 46
 
47
 
835 theseven 48
void clickwheel_thread(void* arg0, void* arg1, void* arg2, void* arg3) ICODE_ATTR;
49
void clickwheel_thread(void* arg0, void* arg1, void* arg2, void* arg3)
132 theseven 50
{
51
    int i;
52
    while (true)
53
    {
54
        wakeup_wait(&clickwheel_wakeup, TIMEOUT_BLOCK);
198 theseven 55
        DEBUGF("Got clickwheel packet");
132 theseven 56
        uint32_t mode = enter_critical_section();
57
        uint32_t data = clickwheel_packet;
58
        leave_critical_section(mode);
198 theseven 59
        DEBUGF("Acquired clickwheel packet: %08X", data);
132 theseven 60
        if ((data & 0x800000FF) == 0x8000001A)
61
        {
62
            int newbuttons = (data >> 8) & 0x1f;
63
            int newpos = (data >> 16) & 0xff;
64
            bool newtouched = (data & 0x40000000) ? true : false;
65
 
198 theseven 66
            DEBUGF("This is a change packet, button state: %02X, position: %02d, touched: %d",
67
                   newbuttons, newpos, newtouched);
132 theseven 68
            int buttonschanged = oldbuttons ^ newbuttons;
198 theseven 69
            DEBUGF("Changed buttons: %02X", buttonschanged);
132 theseven 70
            for (i = 0; i < 5; i++)
71
                if ((buttonschanged >> i) & 1)
72
                {
73
                    if ((oldbuttons >> i) & 1) button_send_event(BUTTON_RELEASE, i, 0);
74
                    else button_send_event(BUTTON_PRESS, i, 0);
75
                }
76
 
77
            if (newtouched)
78
            {
393 theseven 79
                int distance = 0;
132 theseven 80
                if (!oldtouched) button_send_event(WHEEL_TOUCH, 0, newpos);
393 theseven 81
                else distance = newpos - oldpos;
132 theseven 82
                button_send_event(WHEEL_POSITION, 0, newpos);
198 theseven 83
                DEBUGF("Time since last packet: %d microseconds", USEC_TIMER - lastpacket);
84
                if (TIMEOUT_EXPIRED(lastpacket, 200000))
85
                {
86
                    DEBUGF("Resetting accel due to timeout");
87
                    packets = 10;
88
                }
89
                else if (lastdiff * distance < 0)
90
                {
91
                    DEBUGF("Resetting accel due to direction change");
92
                    packets = 10;
93
                }
132 theseven 94
                else packets++;
138 theseven 95
                lastdiff = distance;
96
                if (packets > 200) packets = 200;
132 theseven 97
                if (distance < -48) distance += 96;
98
                else if (distance > 48) distance -= 96;
198 theseven 99
                DEBUGF("Wheel moved %d units without accel", distance);
539 theseven 100
                button_send_event(WHEEL_MOVED, 0, distance);
198 theseven 101
                DEBUGF("Wheel moved %d units with accel", distance * packets);
539 theseven 102
                button_send_event(WHEEL_MOVED_ACCEL, 0, distance * packets);
138 theseven 103
                collect += distance * packets;
104
                enum button_event e = collect > 0 ? WHEEL_FORWARD : WHEEL_BACKWARD;
105
                int data = (collect > 0 ? collect : -collect) / 128;
106
                if (data) button_send_event(e, 0, data);
107
                collect %= 128;
198 theseven 108
                DEBUGF("Wheel moved %d steps (%d left)", data, collect);
132 theseven 109
            }
110
            else if (oldtouched)
111
            {
198 theseven 112
                DEBUGF("Wheel was untouched");
132 theseven 113
                button_send_event(WHEEL_POSITION, 0, newpos);
114
                button_send_event(WHEEL_UNTOUCH, 0, newpos);
138 theseven 115
                collect = 0;
116
                packets = 0;
117
                lastdiff = 0;
132 theseven 118
            }
119
 
120
            oldbuttons = newbuttons;
121
            oldpos = newpos;
122
            oldtouched = newtouched;
123
            lastpacket = USEC_TIMER;
124
        }
198 theseven 125
        else if ((data & 0x8000FFFF) == 0x8000023A)
126
        {
127
            if (data & 0x1F0000) oldbuttons = (data >> 16) & 0x1F;
128
            DEBUGF("This is an init packet, button state: %02X", oldbuttons);
968 theseven 129
            if (!wheel_initialized)
130
            {
131
                wheel_initialized = true;
132
                wakeup_signal(&clickwheel_init_wakeup);
133
            }
198 theseven 134
        }
132 theseven 135
    }
136
}
137
 
138
 
968 theseven 139
int clickwheel_init()
132 theseven 140
{
141
    wakeup_init(&clickwheel_wakeup);
968 theseven 142
    wakeup_init(&clickwheel_init_wakeup);
143
    wheel_initialized = false;
132 theseven 144
    oldtouched = false;
145
    oldbuttons = 0;
146
    lastpacket = 0;
138 theseven 147
    collect = 0;
148
    lastdiff = 0;
132 theseven 149
    PWRCON(1) &= ~1;
150
    PCON15 = (PCON15 & ~0xFFFF0000) | 0x22220000;
151
    PUNK15 = 0xF0;
841 theseven 152
    PCON10 = (PCON10 & ~0xFF0) | 0x10;
153
    WHEELINT = 7;
154
    WHEEL10 = 1;
155
    INTMSK |= 1 << IRQ_WHEEL;
132 theseven 156
    WHEEL08 = 0x3A980;
157
    WHEEL00 = 0x280000;
841 theseven 158
    while (WHEEL0C & 4) yield();
132 theseven 159
    PDAT10 |= 2;
160
    WHEELTX = 0x8000023A;
161
    WHEEL04 |= 1;
162
    PDAT10 &= ~2;
841 theseven 163
    thread_create(&clickwheel_thread_handle, "Clickwheel dispatcher", clickwheel_thread,
164
                  clickwheel_stack, sizeof(clickwheel_stack), OS_THREAD, 200, true,
835 theseven 165
                  NULL, NULL, NULL, NULL);
968 theseven 166
    wakeup_wait(&clickwheel_init_wakeup, 100000);
167
    if (!wheel_initialized) RET_ERR(0);
168
    return 0;
132 theseven 169
}
170
 
171
void INT_WHEEL(void) ICODE_ATTR;
172
void INT_WHEEL()
173
{
174
    uint32_t events = WHEELINT;
175
    if (events & 1)
176
    {
177
        clickwheel_packet = WHEELRX;
178
        wakeup_signal(&clickwheel_wakeup);
179
    }
841 theseven 180
    WHEELINT = events;
132 theseven 181
}
182
 
183
uint32_t clickwheel_get_state()
184
{
185
    return (oldtouched << 15) | (oldpos << 8) | oldbuttons;
186
}