Index: apps/action.c =================================================================== --- apps/action.c (revision 20563) +++ apps/action.c (working copy) @@ -34,6 +34,10 @@ #include "settings.h" #include "pcmbuf.h" +#ifdef HAVE_HARDWARE_CLICK +#include "piezo.h" +#endif + static int last_button = BUTTON_NONE|BUTTON_REL; /* allow the ipod wheel to work on startup */ static intptr_t last_data = 0; @@ -130,9 +134,69 @@ #if CONFIG_CODEC == SWCODEC /* Produce keyclick */ if (global_settings.keyclick && !(button & BUTTON_REL)) - if (!(button & BUTTON_REPEAT) || global_settings.keyclick_repeats) - pcmbuf_beep(4000, KEYCLICK_DURATION, 2500*global_settings.keyclick); + { + if (!(button & BUTTON_REPEAT) || + (button & (BUTTON_SCROLL_FWD | BUTTON_SCROLL_BACK)) || + global_settings.keyclick_repeats) + { + switch (context) + { + case CONTEXT_WPS: + /* Reduce volume clicks by clickwheel to every 8dB */ + if (button & BUTTON_SCROLL_FWD) + if ((global_settings.volume+1) % 8 != 0) + break; + if (button & BUTTON_SCROLL_BACK) + if ((global_settings.volume-1) % 8 != 0) + break; + pcmbuf_beep(4000, KEYCLICK_DURATION, 2500*global_settings.keyclick); + break; + case CONTEXT_MAINMENU: + case CONTEXT_LIST: + case CONTEXT_TREE: + /* Don't make clickwheel click here - look in gui list handling */ + if (button & (BUTTON_SCROLL_FWD | BUTTON_SCROLL_BACK)) + break; + default: + pcmbuf_beep(4000, KEYCLICK_DURATION, 2500*global_settings.keyclick); + break; + } + } + } +#ifdef HAVE_HARDWARE_CLICK + /* Produce speaker click */ + if (global_settings.keyclick_hardware && !(button & BUTTON_REL)) + { + if (!(button & BUTTON_REPEAT) || + (button & (BUTTON_SCROLL_FWD | BUTTON_SCROLL_BACK)) || + global_settings.keyclick_repeats) + { + switch (context) + { + case CONTEXT_WPS: + /* Reduce volume clicks by clickwheel to every 8dB */ + if (button & BUTTON_SCROLL_FWD) + if ((global_settings.volume+1) % 8 != 0) + break; + if (button & BUTTON_SCROLL_BACK) + if ((global_settings.volume-1) % 8 != 0) + break; + piezo_button_beep(false, false); + break; + case CONTEXT_MAINMENU: + case CONTEXT_LIST: + case CONTEXT_TREE: + /* Don't make clickwheel click here - look in gui list handling */ + if (button & (BUTTON_SCROLL_FWD | BUTTON_SCROLL_BACK)) + break; + default: + piezo_button_beep(false, false); + break; + } + } + } #endif +#endif if ((context != last_context) && ((last_button & BUTTON_REL) == 0)) { Index: apps/features.txt =================================================================== --- apps/features.txt (revision 20563) +++ apps/features.txt (working copy) @@ -195,3 +195,7 @@ #if defined(HAVE_TOUCHSCREEN) touchscreen #endif + +#if defined(HAVE_HARDWARE_CLICK) +hardware_click +#endif Index: apps/gui/list.c =================================================================== --- apps/gui/list.c (revision 20563) +++ apps/gui/list.c (working copy) @@ -41,6 +41,13 @@ #include "viewport.h" #include "list.h" +#if CONFIG_CODEC == SWCODEC +#include "pcmbuf.h" +#ifdef HAVE_HARDWARE_CLICK +#include "piezo.h" +#endif +#endif + #ifdef HAVE_LCD_CHARCELLS #define SCROLL_LIMIT 1 #else @@ -335,11 +342,27 @@ new_selection = gui_list->selected_item + offset; if (new_selection >= gui_list->nb_items) { +#if CONFIG_CODEC == SWCODEC + if (global_settings.keyclick && !gui_list->limit_scroll) + pcmbuf_beep(4000, KEYCLICK_DURATION, 2500*global_settings.keyclick); +#ifdef HAVE_HARDWARE_CLICK + if (global_settings.keyclick_hardware && !gui_list->limit_scroll) + piezo_button_beep(false, false); +#endif +#endif gui_list->selected_item = gui_list->limit_scroll ? gui_list->nb_items - gui_list->selected_size : 0; } else if (new_selection < 0) { +#if CONFIG_CODEC == SWCODEC + if (global_settings.keyclick && !gui_list->limit_scroll) + pcmbuf_beep(4000, KEYCLICK_DURATION, 2500*global_settings.keyclick); +#ifdef HAVE_HARDWARE_CLICK + if (global_settings.keyclick_hardware && !gui_list->limit_scroll) + piezo_button_beep(false, false); +#endif +#endif gui_list->selected_item = gui_list->limit_scroll ? 0 : gui_list->nb_items - gui_list->selected_size; } @@ -372,7 +395,18 @@ } return; } - else gui_list->selected_item += offset; + else + { +#if CONFIG_CODEC == SWCODEC + if (global_settings.keyclick) + pcmbuf_beep(4000, KEYCLICK_DURATION, 2500*global_settings.keyclick); +#ifdef HAVE_HARDWARE_CLICK + if (global_settings.keyclick_hardware) + piezo_button_beep(false, false); +#endif +#endif + gui_list->selected_item += offset; + } gui_synclist_select_item(gui_list, gui_list->selected_item); } Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 20563) +++ apps/lang/english.lang (working copy) @@ -11614,6 +11614,40 @@ + id: LANG_KEYCLICK_SOFTWARE + desc: in keyclick settings menu + user: core + + *: none + hardware_click: "Headphone Keyclick" + + + *: none + hardware_click: "Headphone Keyclick" + + + *: none + hardware_click: "Headphone Keyclick" + + + + id: LANG_KEYCLICK_HARDWARE + desc: in keyclick settings menu + user: core + + *: none + hardware_click: "Speaker Keyclick" + + + *: none + hardware_click: "Speaker Keyclick" + + + *: none + hardware_click: "Speaker Keyclick" + + + id: LANG_KEYCLICK_REPEATS desc: in keyclick settings menu user: core Index: apps/main.c =================================================================== --- apps/main.c (revision 20563) +++ apps/main.c (working copy) @@ -109,6 +109,10 @@ #include "m5636.h" #endif +#ifdef HAVE_HARDWARE_CLICK +#include "piezo.h" +#endif + #include "cuesheet.h" #ifdef SIMULATOR @@ -599,6 +603,9 @@ #ifdef HAVE_ACCESSORY_SUPPLY accessory_supply_set(global_settings.accessory_supply); #endif +#ifdef HAVE_HARDWARE_CLICK + piezo_init(); +#endif } #ifdef CPU_PP Index: apps/menus/settings_menu.c =================================================================== --- apps/menus/settings_menu.c (revision 20563) +++ apps/menus/settings_menu.c (working copy) @@ -220,9 +220,15 @@ #if CONFIG_CODEC == SWCODEC MENUITEM_SETTING(keyclick, &global_settings.keyclick, NULL); MENUITEM_SETTING(keyclick_repeats, &global_settings.keyclick_repeats, NULL); +#ifdef HAVE_HARDWARE_CLICK +MENUITEM_SETTING(keyclick_hardware, &global_settings.keyclick_hardware, NULL); MAKE_MENU(keyclick_menu, ID2P(LANG_KEYCLICK), 0, Icon_NOICON, + &keyclick, &keyclick_hardware, &keyclick_repeats); +#else +MAKE_MENU(keyclick_menu, ID2P(LANG_KEYCLICK), 0, Icon_NOICON, &keyclick, &keyclick_repeats); #endif +#endif #if CONFIG_CODEC == MAS3507D Index: apps/settings.h =================================================================== --- apps/settings.h (revision 20563) +++ apps/settings.h (working copy) @@ -734,6 +734,11 @@ /* If values are just added to the end, no need to bump plugin API version. */ /* new stuff to be added at the end */ +#if CONFIG_CODEC == SWCODEC +#ifdef HAVE_HARDWARE_CLICK + bool keyclick_hardware; /* hardware piezo keyclick */ +#endif +#endif }; /** global variables **/ Index: apps/settings_list.c =================================================================== --- apps/settings_list.c (revision 20563) +++ apps/settings_list.c (working copy) @@ -1430,12 +1430,16 @@ #endif /* HAVE_WHEEL_ACCELERATION */ #if CONFIG_CODEC == SWCODEC /* keyclick */ - CHOICE_SETTING(0, keyclick, LANG_KEYCLICK, 0, + CHOICE_SETTING(0, keyclick, LANG_KEYCLICK_SOFTWARE, 0, "keyclick", "off,weak,moderate,strong", NULL, 4, ID2P(LANG_OFF), ID2P(LANG_WEAK), ID2P(LANG_MODERATE), ID2P(LANG_STRONG)), OFFON_SETTING(0, keyclick_repeats, LANG_KEYCLICK_REPEATS, false, "keyclick repeats", NULL), +#ifdef HAVE_HARDWARE_CLICK + OFFON_SETTING(0, keyclick_hardware, LANG_KEYCLICK_HARDWARE, false, + "hardware keyclick", NULL), +#endif #endif /* CONFIG_CODEC == SWCODEC */ TEXT_SETTING(0, playlist_catalog_dir, "playlist catalog directory", PLAYLIST_CATALOG_DEFAULT_DIR, NULL, NULL), Index: firmware/export/config-ipod4g.h =================================================================== --- firmware/export/config-ipod4g.h (revision 20563) +++ firmware/export/config-ipod4g.h (working copy) @@ -187,6 +187,8 @@ /* Define this if you can read an absolute wheel position */ #define HAVE_WHEEL_POSITION +#define HAVE_HARDWARE_CLICK + #define BOOTFILE_EXT "ipod" #define BOOTFILE "rockbox." BOOTFILE_EXT #define BOOTDIR "/.rockbox" Index: firmware/export/config-ipodcolor.h =================================================================== --- firmware/export/config-ipodcolor.h (revision 20563) +++ firmware/export/config-ipodcolor.h (working copy) @@ -164,6 +164,8 @@ /* Define this if you can read an absolute wheel position */ #define HAVE_WHEEL_POSITION +#define HAVE_HARDWARE_CLICK + #define BOOTFILE_EXT "ipod" #define BOOTFILE "rockbox." BOOTFILE_EXT #define BOOTDIR "/.rockbox" Index: firmware/export/config-ipodmini.h =================================================================== --- firmware/export/config-ipodmini.h (revision 20563) +++ firmware/export/config-ipodmini.h (working copy) @@ -180,6 +180,8 @@ /* Define this if you have adjustable CPU frequency */ #define HAVE_ADJUSTABLE_CPU_FREQ +#define HAVE_HARDWARE_CLICK + #define BOOTFILE_EXT "ipod" #define BOOTFILE "rockbox." BOOTFILE_EXT #define BOOTDIR "/.rockbox" Index: firmware/export/config-ipodmini2g.h =================================================================== --- firmware/export/config-ipodmini2g.h (revision 20563) +++ firmware/export/config-ipodmini2g.h (working copy) @@ -191,6 +191,8 @@ /* Define this if you can read an absolute wheel position */ #define HAVE_WHEEL_POSITION +#define HAVE_HARDWARE_CLICK + #define BOOTFILE_EXT "ipod" #define BOOTFILE "rockbox." BOOTFILE_EXT #define BOOTDIR "/.rockbox" Index: firmware/export/config-ipodnano.h =================================================================== --- firmware/export/config-ipodnano.h (revision 20563) +++ firmware/export/config-ipodnano.h (working copy) @@ -174,6 +174,8 @@ /* Define this if you can read an absolute wheel position */ #define HAVE_WHEEL_POSITION +#define HAVE_HARDWARE_CLICK + #define BOOTFILE_EXT "ipod" #define BOOTFILE "rockbox." BOOTFILE_EXT #define BOOTDIR "/.rockbox" Index: firmware/export/config-ipodvideo.h =================================================================== --- firmware/export/config-ipodvideo.h (revision 20563) +++ firmware/export/config-ipodvideo.h (working copy) @@ -188,6 +188,8 @@ /* Define this if you can read an absolute wheel position */ #define HAVE_WHEEL_POSITION +#define HAVE_HARDWARE_CLICK + /* define this if the device has larger sectors when accessed via USB */ /* (only relevant in disk.c, fat.c now always supports large virtual sectors) */ #define MAX_LOG_SECTOR_SIZE 2048 Index: firmware/export/thread.h =================================================================== --- firmware/export/thread.h (revision 20563) +++ firmware/export/thread.h (working copy) @@ -61,9 +61,17 @@ #if CONFIG_CODEC == SWCODEC #ifdef HAVE_RECORDING -#define BASETHREADS 17 + #ifdef HAVE_HARDWARE_CLICK + #define BASETHREADS 18 + #else + #define BASETHREADS 17 + #endif #else -#define BASETHREADS 16 + #ifdef HAVE_HARDWARE_CLICK + #define BASETHREADS 17 + #else + #define BASETHREADS 16 + #endif #endif #else Index: firmware/SOURCES =================================================================== --- firmware/SOURCES (revision 20563) +++ firmware/SOURCES (working copy) @@ -887,6 +887,7 @@ target/arm/ipod/adc-ipod-pcf.c target/arm/ipod/backlight-4g_color.c target/arm/ipod/button-clickwheel.c +target/arm/ipod/piezo.c target/arm/ipod/lcd-as-gray.S target/arm/ipod/lcd-gray.c target/arm/ipod/power-ipod.c @@ -905,6 +906,7 @@ target/arm/ipod/adc-ipod-pcf.c target/arm/ipod/backlight-4g_color.c target/arm/ipod/button-clickwheel.c +target/arm/ipod/piezo.c target/arm/ipod/lcd-color_nano.c target/arm/ipod/power-ipod.c target/arm/ipod/powermgmt-ipod-pcf.c @@ -922,6 +924,7 @@ target/arm/ipod/adc-ipod-pcf.c target/arm/ipod/backlight-nano_video.c target/arm/ipod/button-clickwheel.c +target/arm/ipod/piezo.c target/arm/ipod/lcd-color_nano.c target/arm/ipod/power-ipod.c target/arm/ipod/powermgmt-ipod-pcf.c @@ -939,6 +942,7 @@ target/arm/ipod/adc-ipod-pcf.c target/arm/ipod/backlight-nano_video.c target/arm/ipod/button-clickwheel.c +target/arm/ipod/piezo.c target/arm/ipod/power-ipod.c target/arm/ipod/powermgmt-ipod-pcf.c target/arm/ipod/video/lcd-as-video.S @@ -990,6 +994,7 @@ target/arm/ipod/adc-ipod-pcf.c target/arm/ipod/backlight-mini1g_mini2g.c target/arm/ipod/button-mini1g.c +target/arm/ipod/piezo.c target/arm/ipod/lcd-as-gray.S target/arm/ipod/lcd-gray.c target/arm/ipod/power-ipod.c @@ -1008,6 +1013,7 @@ target/arm/ipod/adc-ipod-pcf.c target/arm/ipod/backlight-mini1g_mini2g.c target/arm/ipod/button-clickwheel.c +target/arm/ipod/piezo.c target/arm/ipod/lcd-as-gray.S target/arm/ipod/lcd-gray.c target/arm/ipod/power-ipod.c Index: firmware/target/arm/ipod/piezo.c =================================================================== --- firmware/target/arm/ipod/piezo.c (revision 0) +++ firmware/target/arm/ipod/piezo.c (revision 0) @@ -0,0 +1,206 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006-2007 Robert Keevil + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "thread.h" +#include "system.h" +#include "kernel.h" +#include "usb.h" +#include "logf.h" +#include "piezo.h" + +#define PIEZO_HZ_CONVERSION 91225 +/* conversion factor based on the following data + + period Hz + 10 8547 + 20 4465 + 30 3024 + 40 2286 + 50 1846 + 60 1537 + 70 1320 + 80 1165 + 90 1030 + 100 928 + + someone with better recording/analysing equipment should be able + to get more accurate figures +*/ + +static long piezo_stack[DEFAULT_STACK_SIZE/sizeof(long)]; +static const char piezo_thread_name[] = "piezo"; +static struct event_queue piezo_queue; +static unsigned int duration; +static bool beeping; + +enum { + Q_PIEZO_BEEP = 1, + Q_PIEZO_BEEP_FOR_TICK, + Q_PIEZO_BEEP_FOR_USEC, + Q_PIEZO_STOP +}; + +static inline void piezo_hw_init(void) +{ + logf("PIEZO: hw_init"); + outl(inl(0x70000010) & ~0xc, 0x70000010); + outl(inl(0x6000600c) | 0x20000, 0x6000600c); /* enable device */ +} + +static void piezo_hw_tick(unsigned int form_and_period) +{ + outl(0x80000000 | form_and_period, 0x7000a000); /* set pitch */ +} + +static inline void piezo_hw_stop(void) +{ + outl(0x0, 0x7000a000); /* piezo off */ +} + + +static void piezo_thread(void) +{ + struct queue_event ev; + long piezo_usec_off; + + while(1) + { + queue_wait(&piezo_queue, &ev); + switch(ev.id) + { + case Q_PIEZO_BEEP: + piezo_hw_tick((unsigned int)ev.data); + beeping = true; + break; + case Q_PIEZO_BEEP_FOR_TICK: + piezo_hw_tick((unsigned int)ev.data); + beeping = true; + sleep(duration); + if (beeping) + piezo_hw_stop(); + beeping = false; + /* remove anything that appeared while sleeping */ + queue_clear(&piezo_queue); + break; + case Q_PIEZO_BEEP_FOR_USEC: + piezo_usec_off = USEC_TIMER + duration; + piezo_hw_tick((unsigned int)ev.data); + beeping = true; + while (TIME_BEFORE(USEC_TIMER, piezo_usec_off)) + if (duration >= 5000) yield(); + if (beeping) + piezo_hw_stop(); + beeping = false; + /* remove anything that appeared while sleeping */ + queue_clear(&piezo_queue); + break; + case Q_PIEZO_STOP: + if (beeping) + piezo_hw_stop(); + beeping = false; + break; +#ifndef SIMULATOR + case SYS_USB_CONNECTED: + /*logf("USB: Piezo core");*/ + piezo_hw_stop(); + queue_clear(&piezo_queue); + usb_acknowledge(SYS_USB_CONNECTED_ACK); + usb_wait_for_disconnect(&piezo_queue); + break ; +#endif + case SYS_TIMEOUT: + break; + } + yield(); + } +} + + +void piezo_play(unsigned short inv_freq, unsigned char form) +{ + queue_post(&piezo_queue, Q_PIEZO_BEEP, + (intptr_t)((unsigned int)form << 16 | inv_freq)); +} + +void piezo_play_for_tick(unsigned short inv_freq, + unsigned char form, unsigned int dur) +{ + duration = dur; + queue_post(&piezo_queue, Q_PIEZO_BEEP_FOR_TICK, + (intptr_t)((unsigned int)form << 16 | inv_freq)); +} + +void piezo_play_for_usec(unsigned short inv_freq, + unsigned char form, unsigned int dur) +{ + duration = dur; + queue_post(&piezo_queue, Q_PIEZO_BEEP_FOR_USEC, + (intptr_t)((unsigned int)form << 16 | inv_freq)); +} + +void piezo_stop(void) +{ + queue_post(&piezo_queue, Q_PIEZO_STOP, 0); +} + +void piezo_clear(void) +{ + queue_clear(&piezo_queue); + piezo_stop(); +} + +bool piezo_busy(void) +{ + return !queue_empty(&piezo_queue); +} + +unsigned int piezo_hz(unsigned int hz) +{ + if (hz > 0) + return PIEZO_HZ_CONVERSION/hz; + else + return 0; +} + +void piezo_init(void) +{ + logf("PIEZO: init"); + piezo_hw_init(); + queue_init(&piezo_queue, true); + create_thread(piezo_thread, piezo_stack, sizeof(piezo_stack), 0, + piezo_thread_name IF_PRIO(, PRIORITY_REALTIME) + IF_COP(, CPU)); +} + +void piezo_button_beep(bool beep, bool force) +{ + /* old on clickwheel action - piezo_play_for_usec(50, 0x80, 400); + old on button action - piezo_play_for_usec(50, 0x80, 3000); */ + + if (force) + piezo_clear(); + + if (queue_empty(&piezo_queue)) + { + if (beep) + piezo_play_for_tick(40, 0x80, HZ/5); + else + piezo_play_for_usec(91, 0x80, 4000); + } +} Index: firmware/target/arm/ipod/piezo.h =================================================================== --- firmware/target/arm/ipod/piezo.h (revision 0) +++ firmware/target/arm/ipod/piezo.h (revision 0) @@ -0,0 +1,30 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006-2007 Robert Keevil + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +void piezo_init(void); +void piezo_play(unsigned short inv_freq, unsigned char form); +void piezo_play_for_tick(unsigned short inv_freq, + unsigned char form, unsigned int dur); +void piezo_play_for_usec(unsigned short inv_freq, + unsigned char form, unsigned int dur); +void piezo_stop(void); +void piezo_clear(void); +bool piezo_busy(void); +unsigned int piezo_hz(unsigned int hz); +void piezo_button_beep(bool beep, bool force);