Subversion Repositories freemyipod

Rev

Rev 968 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
304 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
427 farthen 6
//    This file is part of emCORE.
304 theseven 7
//
427 farthen 8
//    emCORE is free software: you can redistribute it and/or
304 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,
304 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/>.
304 theseven 20
//
21
//
22
 
391 theseven 23
 
304 theseven 24
#include "global.h"
25
#include "clickwheel.h"
26
#include "button.h"
27
#include "thread.h"
28
#include "timer.h"
29
#include "s5l8702.h"
30
#include "contextswitch.h"
968 theseven 31
#ifdef TARGET_ipodclassic
32
#include "fat.h"
33
#include "storage_ata.h"
34
#include "../ipodclassic/storage_ata-target.h"
35
#endif
304 theseven 36
 
37
 
38
static struct wakeup clickwheel_wakeup IBSS_ATTR;
968 theseven 39
static struct wakeup clickwheel_init_wakeup INITDATA_ATTR;
304 theseven 40
static volatile uint32_t clickwheel_packet IBSS_ATTR;
429 theseven 41
static struct scheduler_thread clickwheel_thread_handle;
42
static uint32_t clickwheel_stack[0x100] STACK_ATTR;
968 theseven 43
static bool wheel_initialized IBSS_ATTR;
304 theseven 44
static bool oldtouched IBSS_ATTR;
45
static int oldpos IBSS_ATTR;
46
static int oldbuttons IBSS_ATTR;
968 theseven 47
static int lastpacket IBSS_ATTR;
304 theseven 48
static int packets IBSS_ATTR;
49
static int collect IBSS_ATTR;
50
static int lastdiff IBSS_ATTR;
51
 
52
 
835 theseven 53
void clickwheel_thread(void* arg0, void* arg1, void* arg2, void* arg3) ICODE_ATTR;
54
void clickwheel_thread(void* arg0, void* arg1, void* arg2, void* arg3)
304 theseven 55
{
56
    int i;
57
    while (true)
58
    {
59
        wakeup_wait(&clickwheel_wakeup, TIMEOUT_BLOCK);
60
        DEBUGF("Got clickwheel packet");
61
        uint32_t mode = enter_critical_section();
62
        uint32_t data = clickwheel_packet;
63
        leave_critical_section(mode);
64
        DEBUGF("Acquired clickwheel packet: %08X", data);
968 theseven 65
        int newbuttons = (data >> 8) & 0x1f;
304 theseven 66
        if ((data & 0x800000FF) == 0x8000001A)
67
        {
68
            int newpos = (data >> 16) & 0xff;
69
            bool newtouched = (data & 0x40000000) ? true : false;
70
 
71
            DEBUGF("This is a change packet, button state: %02X, position: %02d, touched: %d",
72
                   newbuttons, newpos, newtouched);
968 theseven 73
 
304 theseven 74
            int buttonschanged = oldbuttons ^ newbuttons;
75
            DEBUGF("Changed buttons: %02X", buttonschanged);
76
            for (i = 0; i < 5; i++)
77
                if ((buttonschanged >> i) & 1)
78
                {
79
                    if ((oldbuttons >> i) & 1) button_send_event(BUTTON_RELEASE, i, 0);
80
                    else button_send_event(BUTTON_PRESS, i, 0);
81
                }
82
 
83
            if (newtouched)
84
            {
390 theseven 85
                int distance = 0;
304 theseven 86
                if (!oldtouched) button_send_event(WHEEL_TOUCH, 0, newpos);
390 theseven 87
                else distance = newpos - oldpos;
304 theseven 88
                button_send_event(WHEEL_POSITION, 0, newpos);
89
                DEBUGF("Time since last packet: %d microseconds", USEC_TIMER - lastpacket);
90
                if (TIMEOUT_EXPIRED(lastpacket, 200000))
91
                {
92
                    DEBUGF("Resetting accel due to timeout");
93
                    packets = 10;
94
                }
95
                else if (lastdiff * distance < 0)
96
                {
97
                    DEBUGF("Resetting accel due to direction change");
98
                    packets = 10;
99
                }
100
                else packets++;
101
                lastdiff = distance;
102
                if (packets > 200) packets = 200;
103
                if (distance < -48) distance += 96;
104
                else if (distance > 48) distance -= 96;
105
                DEBUGF("Wheel moved %d units without accel", distance);
503 theseven 106
                button_send_event(WHEEL_MOVED, 0, distance);
304 theseven 107
                DEBUGF("Wheel moved %d units with accel", distance * packets);
503 theseven 108
                button_send_event(WHEEL_MOVED_ACCEL, 0, distance * packets);
304 theseven 109
                collect += distance * packets;
110
                enum button_event e = collect > 0 ? WHEEL_FORWARD : WHEEL_BACKWARD;
111
                int data = (collect > 0 ? collect : -collect) / 128;
112
                if (data) button_send_event(e, 0, data);
113
                collect %= 128;
114
                DEBUGF("Wheel moved %d steps (%d left)", data, collect);
115
            }
116
            else if (oldtouched)
117
            {
118
                DEBUGF("Wheel was untouched");
119
                button_send_event(WHEEL_POSITION, 0, newpos);
120
                button_send_event(WHEEL_UNTOUCH, 0, newpos);
121
                collect = 0;
122
                packets = 0;
123
                lastdiff = 0;
124
            }
125
 
126
            oldpos = newpos;
127
            oldtouched = newtouched;
128
            lastpacket = USEC_TIMER;
129
        }
130
        else if ((data & 0x8000FFFF) == 0x8000023A)
131
        {
968 theseven 132
            if (data & 0x1F0000) newbuttons = (data >> 16) & 0x1F;
133
            DEBUGF("This is an init packet, button state: %02X", newbuttons);
134
            if (!wheel_initialized)
135
            {
136
                wheel_initialized = true;
137
                wakeup_signal(&clickwheel_init_wakeup);
138
            }
304 theseven 139
        }
968 theseven 140
 
141
        #ifdef TARGET_ipodclassic
142
            if (newbuttons == 0x11 && oldbuttons != 0x11)
143
            {
144
                ata_lock_exclusive(TIMEOUT_BLOCK);
145
                flush_fat(true);
146
                ata_sleepnow();
147
            }
148
            else if (newbuttons != 0x11 && oldbuttons == 0x11)
149
                ata_unlock_exclusive();
150
#endif
151
 
152
        oldbuttons = newbuttons;
304 theseven 153
    }
154
}
155
 
156
 
968 theseven 157
int clickwheel_init()
304 theseven 158
{
159
    wakeup_init(&clickwheel_wakeup);
968 theseven 160
    wakeup_init(&clickwheel_init_wakeup);
161
    wheel_initialized = false;
304 theseven 162
    oldtouched = false;
163
    oldbuttons = 0;
164
    lastpacket = 0;
165
    collect = 0;
166
    lastdiff = 0;
841 theseven 167
    PCON(14) = (PCON(14) & ~0xffff0000) | 0x22220000;
304 theseven 168
    PUNA(2) &= ~2;
169
    WHEELINT = 7;
841 theseven 170
    WHEEL10 = 1;
171
    interrupt_enable(IRQ_WHEEL, true);
172
    WHEEL08 = 0x20000;
304 theseven 173
    WHEEL00 = 0x380000;
841 theseven 174
    while (WHEEL0C & 4) yield();
175
    WHEELTX = 0x8000023A;
176
    WHEEL04 |= 1;
177
    thread_create(&clickwheel_thread_handle, "Clickwheel dispatcher", clickwheel_thread,
178
                  clickwheel_stack, sizeof(clickwheel_stack), OS_THREAD, 200, true,
835 theseven 179
                  NULL, NULL, NULL, NULL);
968 theseven 180
    wakeup_wait(&clickwheel_init_wakeup, 100000);
181
    if (!wheel_initialized) RET_ERR(0);
182
    return 0;
304 theseven 183
}
184
 
185
void INT_WHEEL(void) ICODE_ATTR;
186
void INT_WHEEL()
187
{
188
    uint32_t events = WHEELINT;
189
    if (events & 1)
190
    {
191
        clickwheel_packet = WHEELRX;
192
        wakeup_signal(&clickwheel_wakeup);
193
    }
841 theseven 194
    WHEELINT = events;
304 theseven 195
}
196
 
197
uint32_t clickwheel_get_state()
198
{
199
    return (oldtouched << 15) | (oldpos << 8) | oldbuttons;
200
}