Index: firmware/kernel.c =================================================================== --- firmware/kernel.c (revision 31237) +++ firmware/kernel.c (working copy) @@ -1214,7 +1214,7 @@ corelock_unlock(&s->cl); restore_irq(oldlevel); -#if defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval) +#if 0 //defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval) /* No thread switch if IRQ disabled - it's probably called via ISR. * switch_thread would as well enable them anyway. */ if((result & THREAD_SWITCH) && irq_enabled_checkval(oldlevel)) Index: firmware/target/arm/crt0.S =================================================================== --- firmware/target/arm/crt0.S (revision 31237) +++ firmware/target/arm/crt0.S (working copy) @@ -100,17 +100,21 @@ strhi r4, [r2], #4 bhi 1b - /* Set up stack for IRQ mode */ + /* Set up stack for IRQ mode */ msr cpsr_c, #0xd2 ldr sp, =irq_stack - /* Set up stack for FIQ mode */ - msr cpsr_c, #0xd1 - ldr sp, =fiq_stack - /* Let svc, abort and undefined modes use irq stack */ msr cpsr_c, #0xd3 +#if CONFIG_CPU == AS3525 || CONFIG_CPU == AS3525v2 + ldr sp, =svc_stack +#else ldr sp, =irq_stack + + /* Set up stack for FIQ mode */ + msr cpsr_c, #0xd1 + ldr sp, =fiq_stack +#endif msr cpsr_c, #0xd7 ldr sp, =irq_stack msr cpsr_c, #0xdb @@ -159,15 +163,23 @@ b UIE data_abort_handler: - sub r0, lr, #8 + sub r0, lr, #8 mov r1, #2 b UIE +.ltorg + /* 256 words of IRQ stack */ .space 256*4 irq_stack: +#if CONFIG_CPU == AS3525 || CONFIG_CPU == AS3525v2 +/* 512 words of SVC stack */ + .space 1024*4 +svc_stack: +#else /* 256 words of FIQ stack */ .space 256*4 fiq_stack: +#endif end: Index: firmware/target/arm/as3525/system-as3525.c =================================================================== --- firmware/target/arm/as3525/system-as3525.c (revision 31237) +++ firmware/target/arm/as3525/system-as3525.c (working copy) @@ -37,7 +37,7 @@ extern __attribute__((weak,alias("UIRQ"))) void name (void) static void UIRQ (void) __attribute__((interrupt ("IRQ"))); -void irq_handler(void) __attribute__((interrupt ("IRQ"))); +void irq_handler(void) __attribute__((naked, interrupt ("IRQ"))); void fiq_handler(void) __attribute__((interrupt ("FIQ"))); default_interrupt(INT_WATCHDOG); @@ -107,6 +107,11 @@ static const struct { int source; void (*isr) (void); } vec_int_srcs[] = { /* Highest priority at the top of the list */ +#if defined(HAVE_HOTSWAP) || \ + (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING) + /* If GPIOA ISR is interrupted, things seem to go wonky ?? */ + { INT_SRC_GPIOA, INT_GPIOA }, +#endif #ifdef HAVE_RECORDING { INT_SRC_I2SIN, INT_I2SIN }, /* For recording */ #endif @@ -120,10 +125,6 @@ { INT_SRC_TIMER2, INT_TIMER2 }, { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO }, { INT_SRC_AUDIO, INT_AUDIO }, -#if defined(HAVE_HOTSWAP) || \ - (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING) - { INT_SRC_GPIOA, INT_GPIOA, }, -#endif /* Lowest priority at the end of the list */ }; @@ -143,6 +144,10 @@ VIC_VECT_ADDRS[i] = vec_int_srcs[i].isr; VIC_VECT_CNTLS[i] = (1<<5) | vec_int_srcs[i].source; } + + /* Reset priority hardware */ + for (i = 0; i < 32; i++) + *VIC_VECT_ADDR = 0; } void INT_GPIOA(void) @@ -159,8 +164,32 @@ void irq_handler(void) { - (*VIC_VECT_ADDR)(); /* call the isr */ - *VIC_VECT_ADDR = (void*)VIC_VECT_ADDR; /* any write will ack the irq */ + asm volatile ( + "sub lr, lr, #4 \n" /* Create return address */ + "stmfd sp!, { r0-r3, r12, lr } \n" /* Save what gets clobbered */ + "ldr r12, =0xc6010030 \n" /* Obtain VIC address (before SPSR read!) */ + "ldr r12, [r12] \n" + "mrs r14, spsr \n" /* Save SPSR_irq */ + "str r14, [sp, #-4]! \n" + "msr cpsr_c, #0x13 \n" /* Switch to SVC mode, enable IRQ */ + "and r0, sp, #4 \n" /* Align SVC stack to 8 bytes */ + "sub sp, sp, r0 \n" + "stmfd sp!, { r0, lr } \n" /* Save align fudge and LR_svc */ +#if ARM_ARCH >= 5 + "blx r12 \n" /* Call handler */ +#else + "mov lr, pc \n" + "bx r12 \n" +#endif + "ldmfd sp!, { r0, lr } \n" /* Pop align fugde and LR_svc */ + "add sp, sp, r0 \n" /* Undo alignment fudge */ + "msr cpsr_c, #0x92 \n" /* Mask IRQ, return to IRQ mode */ + "ldr r12, [sp], #4 \n" /* Pop SPSR_irq */ + "ldr r14, =0xc6010030 \n" /* Get VIC vector reg */ + "msr spsr_cxsf, r12 \n" /* Restore SPSR_irq */ + "str r14, [r14] \n" /* Ack end of ISR to VIC */ + "ldmfd sp!, { r0-r3, r12, pc }^ \n" /* Restore regs, and RFE */ + ); } void fiq_handler(void) Index: firmware/target/arm/as3525/ascodec-as3525.c =================================================================== --- firmware/target/arm/as3525/ascodec-as3525.c (revision 31237) +++ firmware/target/arm/as3525/ascodec-as3525.c (working copy) @@ -115,7 +115,7 @@ static struct mutex as_mtx; -static int ascodec_enrd0_shadow = 0; +static unsigned long ascodec_enrd0_shadow = 0; static unsigned char *req_data_ptr = NULL; static struct ascodec_request *req_head = NULL; @@ -160,8 +160,8 @@ */ while (i2c_busy()); - /* disable clock - already in IRQ context */ - CGU_PERI &= ~CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; + /* disable clock */ + bitclr32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE); req->status = 1; @@ -434,6 +434,41 @@ return i; } +#if CONFIG_CPU == AS3525v2 +void ascodec_write_pmu(unsigned int index, unsigned int subreg, + unsigned int value) +{ + struct ascodec_request reqs[2]; + + int oldstatus = disable_irq_save(); + /* we submit consecutive requests to make sure no operations happen on the + * i2c bus between selecting the sub register and writing to it */ + ascodec_async_write(AS3543_PMU_ENABLE, 8 | subreg, &reqs[0]); + ascodec_async_write(index, value, &reqs[1]); + restore_irq(oldstatus); + + /* Wait for second request to finish */ + ascodec_wait(&reqs[1]); +} + +int ascodec_read_pmu(unsigned int index, unsigned int subreg) +{ + struct ascodec_request reqs[2]; + + int oldstatus = disable_irq_save(); + /* we submit consecutive requests to make sure no operations happen on the + * i2c bus between selecting the sub register and reading it */ + ascodec_async_write(AS3543_PMU_ENABLE, subreg, &reqs[0]); + ascodec_async_read(index, 1, &reqs[1], NULL); + restore_irq(oldstatus); + + /* Wait for second request to finish */ + ascodec_wait(&reqs[1]); + + return reqs[1].data[0]; +} +#endif /* CONFIG_CPU == AS3525v2 */ + static void ascodec_read_cb(unsigned const char *data, unsigned int len) { if (UNLIKELY(len != 3)) /* some error happened? */ @@ -492,7 +527,7 @@ bool ascodec_endofch(void) { bool ret = ascodec_enrd0_shadow & CHG_ENDOFCH; - ascodec_enrd0_shadow &= ~CHG_ENDOFCH; // clear interrupt + bitclr32(&ascodec_enrd0_shadow, CHG_ENDOFCH); /* clear interrupt */ return ret; } Index: firmware/target/arm/as3525/ascodec-target.h =================================================================== --- firmware/target/arm/as3525/ascodec-target.h (revision 31237) +++ firmware/target/arm/as3525/ascodec-target.h (working copy) @@ -67,27 +67,9 @@ bool ascodec_chg_status(void); #if CONFIG_CPU == AS3525v2 -static inline void ascodec_write_pmu(unsigned int index, unsigned int subreg, - unsigned int value) -{ - /* we disable interrupts to make sure no operation happen on the i2c bus - * between selecting the sub register and writing to it */ - int oldstatus = disable_irq_save(); - ascodec_write(AS3543_PMU_ENABLE, 8|subreg); - ascodec_write(index, value); - restore_irq(oldstatus); -} - -static inline int ascodec_read_pmu(unsigned int index, unsigned int subreg) -{ - /* we disable interrupts to make sure no operation happen on the i2c bus - * between selecting the sub register and reading it */ - int oldstatus = disable_irq_save(); - ascodec_write(AS3543_PMU_ENABLE, subreg); - int ret = ascodec_read(index); - restore_irq(oldstatus); - return ret; -} +void ascodec_write_pmu(unsigned int index, unsigned int subreg, + unsigned int value); +int ascodec_read_pmu(unsigned int index, unsigned int subreg); #endif /* CONFIG_CPU == AS3525v2 */ static inline void ascodec_write_charger(int value) Index: firmware/target/arm/as3525/sd-as3525v2.c =================================================================== --- firmware/target/arm/as3525/sd-as3525v2.c (revision 31237) +++ firmware/target/arm/as3525/sd-as3525v2.c (working copy) @@ -1055,10 +1055,12 @@ void sd_gpioa_isr(void) { static struct timeout sd1_oneshot; + if (GPIOA_MIS & EXT_SD_BITS) + { timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); - /* acknowledge interrupt */ - GPIOA_IC = EXT_SD_BITS; + GPIOA_IC = EXT_SD_BITS; /* acknowledge interrupt */ + } } #endif /* HAVE_HOTSWAP */ Index: firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c =================================================================== --- firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c (revision 31237) +++ firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c (working copy) @@ -30,6 +30,7 @@ #ifdef HAVE_SCROLLWHEEL #define SCROLLWHEEL_BITS (1<<7|1<<6) +#define SCROLLWHEEL_BITS_POS 6 /* TIMER units */ #define TIMER_TICK (KERNEL_TIMER_FREQ/HZ)/* how long a tick lasts */ #define TIMER_MS (TIMER_TICK/(1000/HZ))/* how long a ms lasts */ @@ -78,10 +79,17 @@ unsigned int btn = BUTTON_NONE; - if (old_wheel_value == wheel_tbl[0][wheel_value]) + if (hold_button) + { + } + else if (old_wheel_value == wheel_tbl[0][wheel_value]) + { btn = BUTTON_SCROLL_FWD; + } else if (old_wheel_value == wheel_tbl[1][wheel_value]) + { btn = BUTTON_SCROLL_BACK; + } if (btn == BUTTON_NONE) { @@ -200,11 +208,13 @@ { #if defined(HAVE_SCROLLWHEEL) /* scroll wheel handling */ - if (GPIOA_MIS & SCROLLWHEEL_BITS) - scrollwheel(GPIOA_PIN_MASK(0xc0) >> 6); + unsigned long bits = GPIOA_MIS & SCROLLWHEEL_BITS; - /* ack interrupt */ - GPIOA_IC = SCROLLWHEEL_BITS; + if (bits) + { + scrollwheel(GPIOA_PIN_MASK(SCROLLWHEEL_BITS) >> SCROLLWHEEL_BITS_POS); + GPIOA_IC = bits; /* ack interrupt */ + } #endif } @@ -225,8 +235,10 @@ int delay = 30; while(delay--) nop; + disable_irq(); + bool ccu_io_bit12 = CCU_IO & (1<<12); - bitclr32(&CCU_IO, 1<<12); + CCU_IO &= ~(1<<12); /* B1 is shared with FM i2c */ bool gpiob_pin0_dir = GPIOB_DIR & (1<<1); @@ -256,8 +268,10 @@ GPIOB_DIR |= 1<<1; if(ccu_io_bit12) - bitset32(&CCU_IO, 1<<12); + CCU_IO |= (1<<12); + enable_irq(); + #ifdef HAS_BUTTON_HOLD #ifndef BOOTLOADER /* light handling */ @@ -265,12 +279,6 @@ { hold_button = hold; backlight_hold_changed(hold); - /* mask scrollwheel irq so we don't need to check for - * the hold button in the isr */ - if (hold) - GPIOA_IE &= ~SCROLLWHEEL_BITS; - else - GPIOA_IE |= SCROLLWHEEL_BITS; } #else hold_button = hold; Index: firmware/target/arm/as3525/sd-as3525.c =================================================================== --- firmware/target/arm/as3525/sd-as3525.c (revision 31237) +++ firmware/target/arm/as3525/sd-as3525.c (working copy) @@ -178,10 +178,12 @@ void sd_gpioa_isr(void) { static struct timeout sd1_oneshot; + if (GPIOA_MIS & EXT_SD_BITS) + { timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); - /* acknowledge interrupt */ - GPIOA_IC = EXT_SD_BITS; + GPIOA_IC = EXT_SD_BITS; /* acknowledge interrupt */ + } } #endif /* HAVE_HOTSWAP */