Index: firmware/target/arm/ipod/button-clickwheel.c
===================================================================
--- firmware/target/arm/ipod/button-clickwheel.c	(revision 13678)
+++ firmware/target/arm/ipod/button-clickwheel.c	(working copy)
@@ -47,6 +47,22 @@
     static bool send_events = true;
 #endif
 
+#define COUNT_PER_REVOLUTION  96
+#define WHEEL_TRIGGER_SPEED    8
+#define SPEED_MAX_X           16
+#define SPEED_DIV             10
+#define SPEED_MIN              5
+#define SPEED_PREDIV        1024
+
+static int wheel_delta;
+static int last_direction = -1;
+static int last_active_tick = 0;
+static int speed = SPEED_MIN;
+static int wheel_repeat = 0;
+static int new_wheel_value = 0;
+static int wheel_keycode = 0;
+static int events_pending = 0;
+
 static void opto_i2c_init(void)
 {
     int i, curr_value;
@@ -89,15 +105,18 @@
 
     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;
+            static int current_speed = 0;
 
             if (status & 0x100)
                 btn |= BUTTON_SELECT;
@@ -111,46 +130,97 @@
                 btn |= BUTTON_MENU;
             if (status & 0x40000000) {
                 /* NB: highest wheel = 0x5F, clockwise increases */
-                int new_wheel_value = (status << 9) >> 25;
+                new_wheel_value = (status << 9) >> 25;
                 whl = new_wheel_value;
                 backlight_on();
                 reset_poweroff_timer();
                 /* The queue should have no other events when scrolling */
-                if (queue_empty(&button_queue) && old_wheel_value >= 0) {
-
+                if (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;
+                    wheel_delta = new_wheel_value - old_wheel_value;
+                    
+                    if (wheel_delta < -COUNT_PER_REVOLUTION/2)
+                    {
+                        wheel_delta += COUNT_PER_REVOLUTION; /* Forward wrapping case */
+                    }
+                    else if (wheel_delta > COUNT_PER_REVOLUTION/2)
+                    {
+                        wheel_delta -= COUNT_PER_REVOLUTION; /* Backward wrapping case */
+                    }
 
-                    if (wheel_delta < -48)
-                        wheel_delta += 96; /* Forward wrapping case */
-                    else if (wheel_delta > 48)
-                        wheel_delta -= 96; /* Backward wrapping case */
-
-                    if (wheel_delta > 4) {
+                    if (abs(wheel_delta) > 4 && current_tick != last_active_tick)
+                    {
+                        int absdelta = abs(wheel_delta);
+                        unsigned int diff = current_tick - last_active_tick;
+                        
+                        current_speed = HZ*absdelta/diff;
+                        old_wheel_value = new_wheel_value;
+                        last_active_tick = current_tick;
+                        speed = MAX(SPEED_MIN, current_speed*current_speed/SPEED_PREDIV);
+                    }
+                    else
+                        goto wheel_end;
+                    
+                    if (current_speed <= WHEEL_TRIGGER_SPEED)
+                    {
+                        speed = SPEED_MIN;
+                        events_pending = 0;
+                        goto wheel_end;
+                    }
+                    
+                    if (wheel_delta > 0)
+                    {
                         wheel_keycode = BUTTON_SCROLL_FWD;
-                    } else if (wheel_delta < -4) {
+                        if (last_direction != 1)
+                        {
+                            speed = SPEED_MIN;
+                            events_pending = 0;
+                        }
+                        last_direction = 1;
+                    } 
+                    else 
+                    {
                         wheel_keycode = BUTTON_SCROLL_BACK;
-                    } else goto wheel_end;
-
+                        if (last_direction != 0)
+                        {
+                            speed = SPEED_MIN;
+                            events_pending = 0;
+                        }
+                        last_direction = 0;
+                    } 
 #ifdef HAVE_WHEEL_POSITION
                     if (send_events)
 #endif
                     {
-                        data = (wheel_delta << 16) | new_wheel_value;
-                        queue_post(&button_queue, wheel_keycode | wheel_repeat,
-                                   data);
+                        int i;
+                        int limit;
+                        int data = (wheel_delta << 16) | new_wheel_value;
+                        
+                        events_pending += speed/SPEED_DIV+1;
+                        limit = MIN(QUEUE_LENGTH - queue_count(&button_queue) - 1,
+                                    events_pending);
+                        
+                        for (i = 0; i < limit; i++)
+                        {
+                            queue_post(&button_queue, wheel_keycode | wheel_repeat,
+                                       data);
+                            wheel_repeat = BUTTON_REPEAT;
+                        }
+                        events_pending -= i;
+                        
+                        wheel_repeat = BUTTON_REPEAT;
                     }
-
-                    if (!wheel_repeat) wheel_repeat = BUTTON_REPEAT;
                 }
-
-                old_wheel_value = new_wheel_value;
-            } else if (old_wheel_value >= 0) {
+                else
+                    old_wheel_value = new_wheel_value;
+            }
+            else if (old_wheel_value >= 0) {
                 /* scroll wheel up */
                 old_wheel_value = -1;
                 wheel_repeat = 0;
+                speed = SPEED_MIN;
+                events_pending = 0;
             }
 
         } else if (status == 0xffffffff) {
@@ -221,13 +291,30 @@
     static bool hold_button = false;
     bool hold_button_old;
 
+    if (events_pending > 0)
+    {
+        int i;
+        int limit;
+        int data = (wheel_delta << 16) | new_wheel_value;
+        
+        limit = MIN(QUEUE_LENGTH - queue_count(&button_queue) - 1,
+                    events_pending);
+        
+        for (i = 0; i < limit; i++)
+        {
+            queue_post(&button_queue, wheel_keycode | wheel_repeat,
+                       data);
+        }
+        events_pending -= i;
+    }
+    
     /* normal buttons */
     hold_button_old = hold_button;
     hold_button = button_hold();
 
     if (hold_button != hold_button_old)
         backlight_hold_changed(hold_button);
-
+        
     /* The int_btn variable is set in the button interrupt handler */
     return int_btn;
 }
Index: apps/gui/list.c
===================================================================
--- apps/gui/list.c	(revision 13678)
+++ apps/gui/list.c	(working copy)
@@ -950,8 +950,11 @@
             FOR_NB_SCREENS(i)
                 gui_list_select_at_offset(&(lists->gui_list[i]), -next_item_modifier);
             if (queue_count(&button_queue) < FRAMEDROP_TRIGGER)
+            {
                 gui_synclist_draw(lists);
-            yield();
+                yield();
+            }
+                yield();
             return ACTION_STD_PREV;
 
         case ACTION_STD_NEXT:
@@ -959,8 +962,11 @@
             FOR_NB_SCREENS(i)
                 gui_list_select_at_offset(&(lists->gui_list[i]), next_item_modifier);
             if (queue_count(&button_queue) < FRAMEDROP_TRIGGER)
+            {
                 gui_synclist_draw(lists);
-            yield();
+                yield();
+            }
+                yield();
             return ACTION_STD_NEXT;
 
 #ifdef HAVE_LCD_BITMAP
