diff --git a/apps/gui/list.c b/apps/gui/list.c index 223fc2c..09117ac 100644 --- a/apps/gui/list.c +++ b/apps/gui/list.c @@ -1012,7 +1012,8 @@ bool gui_synclist_do_button(struct gui_synclist * lists, #ifdef HAVE_SCROLLWHEEL int next_item_modifier = button_apply_acceleration(get_action_data(), - WHEEL_ACCELERATION_FACTOR); + global_settings.wheel_accel_start, + global_settings.wheelacceleration); #else static int next_item_modifier = 1; static int last_accel_tick = 0; diff --git a/apps/lang/deutsch.lang b/apps/lang/deutsch.lang index 61c32c5..9d02200 100644 --- a/apps/lang/deutsch.lang +++ b/apps/lang/deutsch.lang @@ -3258,15 +3258,12 @@ user: *: "List Acceleration Speed" - scrollwheel: none *: "Listenbeschleunigung" - scrollwheel: none *: "Listenbeschleunigung" - scrollwheel: none @@ -11359,3 +11356,20 @@ *: "Mitteleuropäisch" + + id: LANG_WHEEL_ACCEL_START + desc: wheel acceleration start + user: + + *: none + scrollwheel: "Wheelspeed for Acceleration" + + + *: none + scrollwheel: "Startwert für Listenbeschleunigung" + + + *: none + scrollwheel: "Startwert für Listenbeschleunigung" + + diff --git a/apps/lang/english.lang b/apps/lang/english.lang index e79f865..e0f7e9d 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -3333,15 +3333,12 @@ user: *: "List Acceleration Speed" - scrollwheel: none *: "List Acceleration Speed" - scrollwheel: none *: "List Acceleration Speed" - scrollwheel: none @@ -11476,3 +11473,21 @@ *: "Say file type" + + id: LANG_WHEEL_ACCEL_START + desc: wheel acceleration start + user: + + *: none + scrollwheel: "Wheelspeed for Acceleration" + + + *: none + scrollwheel: "Wheelspeed for Acceleration" + + + *: none + scrollwheel: "Wheelspeed for Acceleration" + + + diff --git a/apps/menus/display_menu.c b/apps/menus/display_menu.c index a68defd..ae44e38 100644 --- a/apps/menus/display_menu.c +++ b/apps/menus/display_menu.c @@ -252,6 +252,9 @@ MENUITEM_SETTING(jump_scroll_delay, &global_settings.jump_scroll_delay, NULL); MENUITEM_SETTING(list_accel_start_delay, &global_settings.list_accel_start_delay, NULL); MENUITEM_SETTING(list_accel_wait, &global_settings.list_accel_wait, NULL); +#else +MENUITEM_SETTING(wheel_accel_start, &global_settings.wheel_accel_start, NULL); +MENUITEM_SETTING(wheelacceleration, &global_settings.wheelacceleration, NULL); #endif /* HAVE_SCROLLWHEEL */ #ifdef HAVE_LCD_BITMAP int screenscroll_callback(int action,const struct menu_item_ex *this_item) @@ -289,6 +292,9 @@ MAKE_MENU(scroll_settings_menu, ID2P(LANG_SCROLL_MENU), 0, Icon_NOICON, &scroll_paginated, #ifndef HAVE_SCROLLWHEEL &list_accel_start_delay, &list_accel_wait +#else + &wheel_accel_start, + &wheelacceleration #endif ); /* SCROLL MENU */ diff --git a/apps/settings.h b/apps/settings.h index d4498cf..9161a20 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -743,6 +743,9 @@ struct user_settings #ifndef HAVE_SCROLLWHEEL int list_accel_start_delay; /* ms before we start increaseing step size */ int list_accel_wait; /* ms between increases */ +#else + unsigned int wheel_accel_start; /* value in clicks/sec from which acceleration starts */ + unsigned int wheelacceleration; /* type of acceleration (^2/^3/^4) */ #endif #ifdef HAVE_USBSTACK int usb_stack_mode; /* device or host */ diff --git a/apps/settings_list.c b/apps/settings_list.c index d1d8905..6bcfa49 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -242,6 +242,18 @@ static void ff_rewind_min_step_formatter(char *buffer, size_t buffer_size, (void)unit; snprintf(buffer, buffer_size, "%ds", ff_rewind_min_stepvals[val]); } +static long wheel_accel_start_getlang(int value) +{ + if (value == 0) + return LANG_OFF; + return TALK_ID(value, UNIT_INT); +} +static long wheel_accel_getlang(int value) +{ + if (value == 0) + return LANG_OFF; + return TALK_ID(value, UNIT_INT); +} static long scanaccel_getlang(int value) { if (value == 0) @@ -257,6 +269,28 @@ static void scanaccel_formatter(char *buffer, size_t buffer_size, else snprintf(buffer, buffer_size, "2x/%ds", val); } +static void wheel_accel_start_formatter(char *buffer, size_t buffer_size, + int val, const char *unit) +{ + (void)unit; + if (val == 0) + strcpy(buffer, str(LANG_OFF)); + else + snprintf(buffer, buffer_size, "%d °/s", val); +} +static void wheel_accel_formatter(char *buffer, size_t buffer_size, + int val, const char *unit) +{ + (void)unit; + if (val == 0) + strcpy(buffer, str(LANG_OFF)); + else if (val==1) + snprintf(buffer, buffer_size, "(°/s)^2"); + else if (val==2) + snprintf(buffer, buffer_size, "(°/s)^3"); + else + snprintf(buffer, buffer_size, "(°/s)^4"); +} static const unsigned char poweroff_idle_timer_times[] = {0,1,2,3,4,5,6,7,8,9,10,15,30,45,60}; static long poweroff_idle_timer_getlang(int value) @@ -1269,6 +1303,13 @@ const struct settings_list settings[] = { INT_SETTING(0, list_accel_wait, LANG_LISTACCEL_ACCEL_SPEED, 3, "list_accel_wait", UNIT_SEC, 1, 10, 1, scanaccel_formatter, scanaccel_getlang, NULL), +#else + INT_SETTING(0, wheel_accel_start, LANG_WHEEL_ACCEL_START, DEFAULT_WHEEL_ACCEL_START, + "wheel_accel_start", UNIT_INT, 180, 810, 90, + wheel_accel_start_formatter, wheel_accel_start_getlang, NULL), + INT_SETTING(0, wheelacceleration, LANG_LISTACCEL_ACCEL_SPEED, DEFAULT_WHEEL_ACCELERATION, + "wheel_acceleration", UNIT_INT, 1, 3, 1, + wheel_accel_formatter, wheel_accel_getlang, NULL), #endif /* HAVE_SCROLLWHEEL */ #ifdef HAVE_USBSTACK CHOICE_SETTING(0, usb_stack_mode, LANG_USBSTACK_MODE, 0, "usb mode", diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index 000c478..632776b 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c @@ -292,7 +292,7 @@ static void button_tick(void) static void button_boost(bool state) { static bool boosted = false; - + if (state && !boosted) { cpu_boost(true); @@ -323,11 +323,11 @@ long button_get(bool block) else if (pending_count > 2) button_boost(true); #endif - + if ( block || pending_count ) { queue_wait(&button_queue, &ev); - + #if 0 /* Ignore if the event was too old and for simplicity, just * wait for a new button_get() request. */ @@ -337,22 +337,22 @@ long button_get(bool block) button_data = ev.data; return ev.id; } - + return BUTTON_NONE; } long button_get_w_tmo(int ticks) { struct queue_event ev; - + #ifdef HAVE_ADJUSTABLE_CPU_FREQ /* Be sure to keep boosted state. */ if (!queue_empty(&button_queue)) return button_get(true); - + button_boost(false); #endif - + queue_wait_w_tmo(&button_queue, &ev, ticks); if (ev.id == SYS_TIMEOUT) ev.id = BUTTON_NONE; @@ -384,7 +384,7 @@ void button_init(void) button_read(); lastbtn = button_read(); #endif - + tick_add_task(button_tick); reset_poweroff_timer(); @@ -395,7 +395,7 @@ void button_init(void) filter_first_keypress = false; #ifdef HAVE_REMOTE_LCD remote_filter_first_keypress = false; -#endif +#endif #endif } @@ -526,22 +526,44 @@ void button_clear_queue(void) * data: * [31] Use acceleration * [30:24] Message post count (skipped + 1) (1-127) - * [23:0] Velocity - clicks/uS - 0.24 fixed point + * [23:0] [23:0] Velocity - degree/sec * * factor: - * Wheel acceleration scaling factor - x.24 fixed point - - * no greater than what will not overflow 64 bits when multiplied - * by the driver's maximum velocity in (clicks/usec)^2 in 0.24 + * Value in degree/sec -- configurable via settings -- above which + * the accelerated scrolling starts. Factor is internally scaled by + * 1<<16 in respect to the following 32bit integer operations. */ -int button_apply_acceleration(unsigned int data, unsigned int factor) + int button_apply_acceleration(const unsigned int data, + const unsigned int accel_start, + const unsigned int accel_type) { int delta = (data >> 24) & 0x7f; if ((data & (1 << 31)) != 0) { + /* factor = 2^16 / global_settings.wheel_accel_start */ + unsigned int factor = (1<<16)/accel_start; + + /* read driver's velocity from data */ unsigned int v = data & 0xffffff; - v = factor * (unsigned long long)v*v / 0xffffffffffffull; + /* v = 28.4 fixed point */ + v = (factor * v)>>(16-4); + + /* Calculate real numbers item to scroll based upon acceleration + * setting, use correct roundoff */ + switch (accel_type) + { + default: + v = (v*v + (1<< 7))>> 8; + break; + case 2: + v = (v*v*v + (1<<11))>>12; + break; + case 3: + v = (v*v*v*v + (1<<15))>>16; + break; + } if (v > 1) delta *= v; diff --git a/firmware/export/button.h b/firmware/export/button.h index a38385c..da02dcf 100644 --- a/firmware/export/button.h +++ b/firmware/export/button.h @@ -52,7 +52,9 @@ void wheel_send_events(bool send); #endif #ifdef HAVE_SCROLLWHEEL -int button_apply_acceleration(unsigned int data, unsigned int factor); +int button_apply_acceleration(const unsigned int data, + const unsigned int accel_start, + const unsigned int accel_type); #endif #define BUTTON_NONE 0x00000000 diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index 5e9103b..a9eb132 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h @@ -97,9 +97,10 @@ /* define this if the unit uses a scrollwheel for navigation */ #define HAVE_SCROLLWHEEL -/* define wheel acceleration scaling factor */ -/* Range for this target: 0xffffff*(0.0-16.000000894069724921567733381255) */ -#define WHEEL_ACCELERATION_FACTOR (0xffffff*7) +/* define from which rotation speed [degree/sec] on the acceleration starts */ +#define DEFAULT_WHEEL_ACCEL_START 540 +/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */ +#define DEFAULT_WHEEL_ACCELERATION 1 /* define this if you have a flash memory storage */ #define HAVE_FLASH_STORAGE diff --git a/firmware/export/config-ipod4g.h b/firmware/export/config-ipod4g.h index 7d58992..c47effd 100644 --- a/firmware/export/config-ipod4g.h +++ b/firmware/export/config-ipod4g.h @@ -81,6 +81,13 @@ /* Define this for LCD backlight available */ #define HAVE_BACKLIGHT +/* define this if the unit uses a scrollwheel for navigation */ +#define HAVE_SCROLLWHEEL +/* define from which rotation speed [degree/sec] on the acceleration starts */ +#define DEFAULT_WHEEL_ACCEL_START 270 +/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */ +#define DEFAULT_WHEEL_ACCELERATION 3 + /* Define this if you can detect headphones */ #define HAVE_HEADPHONE_DETECTION diff --git a/firmware/export/config-ipodcolor.h b/firmware/export/config-ipodcolor.h index a585090..8a50268 100644 --- a/firmware/export/config-ipodcolor.h +++ b/firmware/export/config-ipodcolor.h @@ -70,6 +70,13 @@ /* Define this for LCD backlight available */ #define HAVE_BACKLIGHT +/* define this if the unit uses a scrollwheel for navigation */ +#define HAVE_SCROLLWHEEL +/* define from which rotation speed [degree/sec] on the acceleration starts */ +#define DEFAULT_WHEEL_ACCEL_START 270 +/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */ +#define DEFAULT_WHEEL_ACCELERATION 3 + /* Define this if you can detect headphones */ #define HAVE_HEADPHONE_DETECTION diff --git a/firmware/export/config-ipodmini2g.h b/firmware/export/config-ipodmini2g.h index 77299dd..cad1727 100644 --- a/firmware/export/config-ipodmini2g.h +++ b/firmware/export/config-ipodmini2g.h @@ -78,6 +78,13 @@ /* We can fade the backlight by using PWM */ #define HAVE_BACKLIGHT_PWM_FADING +/* define this if the unit uses a scrollwheel for navigation */ +#define HAVE_SCROLLWHEEL +/* define from which rotation speed [degree/sec] on the acceleration starts */ +#define DEFAULT_WHEEL_ACCEL_START 270 +/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */ +#define DEFAULT_WHEEL_ACCELERATION 3 + /* Define this if you can detect headphones */ #define HAVE_HEADPHONE_DETECTION diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h index fcba445..c685251 100644 --- a/firmware/export/config-ipodnano.h +++ b/firmware/export/config-ipodnano.h @@ -73,6 +73,13 @@ /* We can fade the backlight by using PWM */ #define HAVE_BACKLIGHT_PWM_FADING +/* define this if the unit uses a scrollwheel for navigation */ +#define HAVE_SCROLLWHEEL +/* define from which rotation speed [degree/sec] on the acceleration starts */ +#define DEFAULT_WHEEL_ACCEL_START 270 +/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */ +#define DEFAULT_WHEEL_ACCELERATION 3 + /* Define this if you can detect headphones */ #define HAVE_HEADPHONE_DETECTION diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h index 9ba4792..88fe899 100644 --- a/firmware/export/config-ipodvideo.h +++ b/firmware/export/config-ipodvideo.h @@ -73,6 +73,13 @@ /* We can fade the backlight by using PWM */ #define HAVE_BACKLIGHT_PWM_FADING +/* define this if the unit uses a scrollwheel for navigation */ +#define HAVE_SCROLLWHEEL +/* define from which rotation speed [degree/sec] on the acceleration starts */ +#define DEFAULT_WHEEL_ACCEL_START 270 +/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */ +#define DEFAULT_WHEEL_ACCELERATION 3 + /* Define this if you can detect headphones */ #define HAVE_HEADPHONE_DETECTION diff --git a/firmware/target/arm/ipod/button-clickwheel.c b/firmware/target/arm/ipod/button-clickwheel.c index 15f3cdd..38176a7 100644 --- a/firmware/target/arm/ipod/button-clickwheel.c +++ b/firmware/target/arm/ipod/button-clickwheel.c @@ -40,6 +40,30 @@ #include "system.h" #include "powermgmt.h" +#define WHEEL_FAST_OFF_TIMEOUT 250000 /* timeout for acceleration = 250ms */ +#define WHEEL_REPEAT_TIMEOUT 250000 /* timeout for button repeat = 250ms */ +#define WHEEL_UNTOUCH_TIMEOUT 150000 /* timeout for untouching wheel = 100ms */ +#define WHEELCLICKS_PER_ROTATION 96 /* wheelclicks per full rotation */ + +/* This amount of clicks is needed for at least scrolling 1 item. Choose small values + * to have high sensitivity but few precision, choose large values to have less + * sensitivity and good precision. */ +#if defined(IPOD_NANO) +#define WHEEL_SENSITIVITY 6 /* iPod nano has smaller wheel, lower sensitivity needed */ +#else +#define WHEEL_SENSITIVITY 4 /* default sensitivity */ +#endif + +int old_wheel_value = -1; +int new_wheel_value = 0; +int repeat = 0; +int wheel_delta = 0; +bool wheel_is_touched = false; +unsigned int accumulated_wheel_delta = 0; +unsigned int wheel_repeat = 0; +unsigned int wheel_velocity = 0; +unsigned long last_wheel_usec = 0; + /* Variable to use for setting button status in interrupt handler */ int int_btn = BUTTON_NONE; #ifdef HAVE_WHEEL_POSITION @@ -82,20 +106,22 @@ static void opto_i2c_init(void) static inline int ipod_4g_button_read(void) { int whl = -1; - + /* The ipodlinux source had a udelay(250) here, but testing has shown that it is not needed - tested on Nano, Color/Photo and Video. */ /* udelay(250);*/ int btn = BUTTON_NONE; unsigned reg = 0x7000c104; - if ((inl(0x7000c104) & 0x4000000) != 0) { + if ((inl(0x7000c104) & 0x4000000) != 0) + { unsigned status = inl(0x7000c140); reg = reg + 0x3C; /* 0x7000c140 */ outl(0x0, 0x7000c140); /* clear interrupt status? */ - if ((status & 0x800000ff) == 0x8000001a) { + if ((status & 0x800000ff) == 0x8000001a) + { static int old_wheel_value IDATA_ATTR = -1; static int wheel_repeat = 0; @@ -109,63 +135,152 @@ static inline int ipod_4g_button_read(void) btn |= BUTTON_PLAY; if (status & 0x1000) btn |= BUTTON_MENU; - if (status & 0x40000000) { - /* NB: highest wheel = 0x5F, clockwise increases */ - int new_wheel_value = (status << 9) >> 25; + if (status & 0x40000000) + { + unsigned long usec = USEC_TIMER; + + /* Highest wheel = 0x5F, clockwise increases */ + new_wheel_value = (status >> 16) & 0x7f; whl = new_wheel_value; + + /* switch on backlight (again), reset power-off timer */ backlight_on(); reset_poweroff_timer(); - /* The queue should have no other events when scrolling */ - if (queue_empty(&button_queue) && old_wheel_value >= 0) { - /* This is for later = BUTTON_SCROLL_TOUCH;*/ - int wheel_delta = new_wheel_value - old_wheel_value; - unsigned long data; - int wheel_keycode; - - if (wheel_delta < -48) - wheel_delta += 96; /* Forward wrapping case */ - else if (wheel_delta > 48) - wheel_delta -= 96; /* Backward wrapping case */ + /* Check whether the scrollwheel was untouched by accident or by will. */ + /* This is needed because wheel may be untoched very shortly during rotation */ + if ( (!wheel_is_touched) && TIME_AFTER(usec, last_wheel_usec + WHEEL_UNTOUCH_TIMEOUT) ) + { + /* wheel has been really untouched -> reset internal variables */ + old_wheel_value = -1; + wheel_velocity = 0; + accumulated_wheel_delta = 0; + wheel_repeat = BUTTON_NONE; + } + else + { + /* wheel was shortly untouched by accident -> leave internal variables */ + wheel_is_touched = true; + } - if (wheel_delta > 4) { + if (old_wheel_value >= 0) + { + /* This is for later = BUTTON_SCROLL_TOUCH;*/ + wheel_delta = new_wheel_value - old_wheel_value; + unsigned int wheel_keycode = BUTTON_NONE; + + /* Taking into account wrapping during transition from highest + * to lowest wheel position and back */ + if (wheel_delta < -WHEELCLICKS_PER_ROTATION/2) + wheel_delta += WHEELCLICKS_PER_ROTATION; /* Forward wrapping case */ + else if (wheel_delta > WHEELCLICKS_PER_ROTATION/2) + wheel_delta -= WHEELCLICKS_PER_ROTATION; /* Backward wrapping case */ + + /* Getting direction and wheel_keycode from wheel_delta. + * Need at least some clicks to be sure to avoid haptic fuzziness */ + if (wheel_delta >= WHEEL_SENSITIVITY) wheel_keycode = BUTTON_SCROLL_FWD; - } else if (wheel_delta < -4) { + else if (wheel_delta <= -WHEEL_SENSITIVITY) wheel_keycode = BUTTON_SCROLL_BACK; - } else goto wheel_end; + else + wheel_keycode = BUTTON_NONE; + + if (wheel_keycode != BUTTON_NONE) + { + long v = (usec - last_wheel_usec) & 0x7fffffff; + + /* undo signedness */ + wheel_delta = (wheel_delta>0) ? wheel_delta : -wheel_delta; + + /* add the current wheel_delta */ + accumulated_wheel_delta += wheel_delta; + + v = v ? (1000000 * wheel_delta) / v : 0; /* clicks/sec = 1000000 * clicks/usec */ + v = (v * 360) / WHEELCLICKS_PER_ROTATION; /* conversion to degree/sec */ + v = (v<0) ? -v : v; /* undo signedness */ + + /* some velocity filtering to smooth things out */ + wheel_velocity = (31 * wheel_velocity + v) / 32; + /* limit to 24 bit */ + wheel_velocity = (wheel_velocity>0xffffff) ? 0xffffff : wheel_velocity; + + /* assume REPEAT = off */ + repeat = 0; + + /* direction reversals must nullify acceleration and accumulator */ + if (wheel_keycode != wheel_repeat) + { + wheel_repeat = wheel_keycode; + wheel_velocity = 0; + accumulated_wheel_delta = 0; + } + /* on same direction REPEAT is assumed when new click is within timeout */ + else if (TIME_BEFORE(usec, last_wheel_usec + WHEEL_REPEAT_TIMEOUT)) + { + repeat = BUTTON_REPEAT; + } + /* timeout nullifies acceleration and accumulator */ + if (TIME_AFTER(usec, last_wheel_usec + WHEEL_FAST_OFF_TIMEOUT)) + { + wheel_velocity = 0; + accumulated_wheel_delta = 0; + } #ifdef HAVE_WHEEL_POSITION - if (send_events) + if (send_events) #endif - { - data = (wheel_delta << 16) | new_wheel_value; - queue_post(&button_queue, wheel_keycode | wheel_repeat, - data); + /* The queue should have no other events when scrolling */ + if (queue_empty(&button_queue)) + { + /* each WHEEL_SENSITIVITY clicks = scrolling 1 item */ + accumulated_wheel_delta /= WHEEL_SENSITIVITY; +#ifdef HAVE_SCROLLWHEEL + /* use data-format for HAVE_SCROLLWHEEL */ + /* always use acceleration mode (1<<31) */ + /* always set message post count to (1<<24) for iPod */ + /* this way the scrolling is always calculated from wheel_velocity */ + queue_post(&button_queue, wheel_keycode | repeat, + (1<<31) | (1 << 24) | wheel_velocity); + +#else + queue_post(&button_queue, wheel_keycode | repeat, + (accumulated_wheel_delta << 16) | new_wheel_value); +#endif + accumulated_wheel_delta = 0; + } + last_wheel_usec = usec; + old_wheel_value = new_wheel_value; } - - if (!wheel_repeat) wheel_repeat = BUTTON_REPEAT; } - - old_wheel_value = new_wheel_value; - } else if (old_wheel_value >= 0) { - /* scroll wheel up */ - old_wheel_value = -1; - wheel_repeat = 0; + else + { + /* scrollwheel was touched for the first time after finger lifting */ + old_wheel_value = new_wheel_value; + wheel_is_touched = true; + } + } + else + { + /* In this case the finger was lifted from the scrollwheel. */ + wheel_is_touched = false; } - } else if (status == 0xffffffff) { + } + else if (status == 0xffffffff) + { opto_i2c_init(); } } -wheel_end: - - if ((inl(reg) & 0x8000000) != 0) { + if ((inl(reg) & 0x8000000) != 0) + { outl(0xffffffff, 0x7000c120); outl(0xffffffff, 0x7000c124); } /* Save the new absolute wheel position */ +#ifdef HAVE_WHEEL_POSITION wheel_position = whl; +#endif return btn; } @@ -174,7 +289,7 @@ int wheel_status(void) { return wheel_position; } - + void wheel_send_events(bool send) { send_events = send; @@ -184,10 +299,10 @@ void wheel_send_events(bool send) void ipod_4g_button_int(void) { CPU_HI_INT_CLR = I2C_MASK; - /* The following delay was 250 in the ipodlinux source, but 50 seems to + /* The following delay was 250 in the ipodlinux source, but 50 seems to work fine - tested on Nano, Color/Photo and Video. */ - udelay(50); - outl(0x0, 0x7000c140); + udelay(50); + outl(0x0, 0x7000c140); int_btn = ipod_4g_button_read(); outl(inl(0x7000c104) | 0xC000000, 0x7000c104); outl(0x400a1f00, 0x7000c100); @@ -202,7 +317,7 @@ void button_init_device(void) opto_i2c_init(); /* hold button - enable as input */ GPIOA_ENABLE |= 0x20; - GPIOA_OUTPUT_EN &= ~0x20; + GPIOA_OUTPUT_EN &= ~0x20; /* hold button - set interrupt levels */ GPIOA_INT_LEV = ~(GPIOA_INPUT_VAL & 0x20); GPIOA_INT_CLR = GPIOA_INT_STAT & 0x20; diff --git a/firmware/target/arm/sandisk/sansa-e200/button-e200.c b/firmware/target/arm/sandisk/sansa-e200/button-e200.c index 5988e16..a74d860 100644 --- a/firmware/target/arm/sandisk/sansa-e200/button-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/button-e200.c @@ -27,6 +27,7 @@ #define WHEEL_REPEAT_INTERVAL 300000 #define WHEEL_FAST_ON_INTERVAL 20000 #define WHEEL_FAST_OFF_INTERVAL 60000 +#define WHEELCLICKS_PER_ROTATION 48 /* wheelclicks per full rotation */ /* Clickwheel */ #ifndef BOOTLOADER @@ -137,10 +138,8 @@ void clickwheel_int(void) unsigned long usec = USEC_TIMER; unsigned v = (usec - last_wheel_usec) & 0x7fffffff; - /* wheel velocity in 0.24 fixed point - clicks/uS */ - - /* velocity cap to 18 bits to allow up to x16 scaling */ - v = (v < 0x40) ? 0xffffff / 0x40 : 0xffffff / v; + v = (v>0) ? 1000000 / v : 0; /* clicks/sec = 1000000 * clicks/usec */ + v = (v>0xffffff) ? 0xffffff : v; /* limit to 24 bit */ /* some velocity filtering to smooth things out */ wheel_velocity = (7*wheel_velocity + v) / 8; @@ -173,12 +172,12 @@ void clickwheel_int(void) else { /* fast ON gets filtered to avoid inadvertent jumps to fast mode */ - if (repeat && wheel_velocity > 0xffffff/WHEEL_FAST_ON_INTERVAL) + if (repeat && wheel_velocity > 1000000/WHEEL_FAST_ON_INTERVAL) { /* moving into fast mode */ wheel_fast_mode = 1 << 31; wheel_click_count = 0; - wheel_velocity = 0xffffff/WHEEL_FAST_OFF_INTERVAL; + wheel_velocity = 1000000/WHEEL_FAST_OFF_INTERVAL; } else if (++wheel_click_count < 2) { @@ -190,7 +189,7 @@ void clickwheel_int(void) } if (TIME_AFTER(current_tick, next_backlight_on) || - v <= 0xffffff/(1000000/4)) + v <= 4) { /* poke backlight to turn it on or maintain it no more often than every 1/4 second*/ @@ -214,7 +213,7 @@ void clickwheel_int(void) if (queue_empty(&button_queue)) { queue_post(&button_queue, btn, wheel_fast_mode | - (wheel_delta << 24) | wheel_velocity); + (wheel_delta << 24) | wheel_velocity*360/WHEELCLICKS_PER_ROTATION); /* message posted - reset delta */ wheel_delta = 1; }