Messages in this thread Patch in this message | | | Date | Fri, 11 Nov 2005 15:07:48 +0100 | From | Takashi Iwai <> | Subject | Re: ALSA in 2.6.14: RTC timer breaks MIDI |
| |
At Thu, 10 Nov 2005 17:48:04 +0100 (CET), Marek Szuba wrote: > > (I'm having problems with access to the ALSA bug tracker, that's why I'm > reporting this issue here) > > Hello everyone, > > A couple of days ago I tried to play a MIDI file on a 2.6.14 box with > emu10k1 for sound (Audigy 2 ZS) and was surprised to hear that the > sequencer no longer works - or to be exact, when having it play any MIDI > song it only starts playing the first note in each channel and leaves them > like that, playing the same tones until the player's closed. Going back to > 2.6.13 made the problem go away; on the other hand, even an upgrade of > ALSA userspace components to the latest version doesn't help with 2.6.14.
A known problem. Try the patch below.
Takashi
--- diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -149,8 +149,22 @@ static void get_rtc_alm_time (struct rtc #ifdef RTC_IRQ static void rtc_dropped_irq(unsigned long data); -static void set_rtc_irq_bit(unsigned char bit); -static void mask_rtc_irq_bit(unsigned char bit); +static void set_rtc_irq_bit_locked(unsigned char bit); +static void mask_rtc_irq_bit_locked(unsigned char bit); + +static inline void set_rtc_irq_bit(unsigned char bit) +{ + spin_lock_irq(&rtc_lock); + set_rtc_irq_bit_locked(bit); + spin_unlock_irq(&rtc_lock); +} + +static void mask_rtc_irq_bit(unsigned char bit) +{ + spin_lock_irq(&rtc_lock); + mask_rtc_irq_bit_locked(bit); + spin_unlock_irq(&rtc_lock); +} #endif static int rtc_proc_open(struct inode *inode, struct file *file); @@ -401,18 +415,19 @@ static int rtc_do_ioctl(unsigned int cmd } case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ { - mask_rtc_irq_bit(RTC_PIE); + unsigned long flags; /* can be called from isr via rtc_control() */ + spin_lock_irqsave (&rtc_lock, flags); + mask_rtc_irq_bit_locked(RTC_PIE); if (rtc_status & RTC_TIMER_ON) { - spin_lock_irq (&rtc_lock); rtc_status &= ~RTC_TIMER_ON; del_timer(&rtc_irq_timer); - spin_unlock_irq (&rtc_lock); } + spin_unlock_irqrestore (&rtc_lock, flags); return 0; } case RTC_PIE_ON: /* Allow periodic ints */ { - + unsigned long flags; /* can be called from isr via rtc_control() */ /* * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. @@ -421,14 +436,14 @@ static int rtc_do_ioctl(unsigned int cmd (!capable(CAP_SYS_RESOURCE))) return -EACCES; + spin_lock_irqsave (&rtc_lock, flags); if (!(rtc_status & RTC_TIMER_ON)) { - spin_lock_irq (&rtc_lock); rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; add_timer(&rtc_irq_timer); rtc_status |= RTC_TIMER_ON; - spin_unlock_irq (&rtc_lock); } - set_rtc_irq_bit(RTC_PIE); + set_rtc_irq_bit_locked(RTC_PIE); + spin_unlock_irqrestore (&rtc_lock, flags); return 0; } case RTC_UIE_OFF: /* Mask ints from RTC updates. */ @@ -609,6 +624,7 @@ static int rtc_do_ioctl(unsigned int cmd { int tmp = 0; unsigned char val; + unsigned long flags; /* can be called from isr via rtc_control() */ /* * The max we can do is 8192Hz. @@ -631,9 +647,9 @@ static int rtc_do_ioctl(unsigned int cmd if (arg != (1<<tmp)) return -EINVAL; - spin_lock_irq(&rtc_lock); + spin_lock_irqsave(&rtc_lock, flags); if (hpet_set_periodic_freq(arg)) { - spin_unlock_irq(&rtc_lock); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } rtc_freq = arg; @@ -641,7 +657,7 @@ static int rtc_do_ioctl(unsigned int cmd val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; val |= (16 - tmp); CMOS_WRITE(val, RTC_FREQ_SELECT); - spin_unlock_irq(&rtc_lock); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } #endif @@ -844,12 +860,15 @@ int rtc_control(rtc_task_t *task, unsign #ifndef RTC_IRQ return -EIO; #else - spin_lock_irq(&rtc_task_lock); + unsigned long flags; + if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET) + return -EINVAL; + spin_lock_irqsave(&rtc_task_lock, flags); if (rtc_callback != task) { - spin_unlock_irq(&rtc_task_lock); + spin_unlock_irqrestore(&rtc_task_lock, flags); return -ENXIO; } - spin_unlock_irq(&rtc_task_lock); + spin_unlock_irqrestore(&rtc_task_lock, flags); return rtc_do_ioctl(cmd, arg, 1); #endif } @@ -1306,40 +1325,32 @@ static void get_rtc_alm_time(struct rtc_ * meddles with the interrupt enable/disable bits. */ -static void mask_rtc_irq_bit(unsigned char bit) +static void mask_rtc_irq_bit_locked(unsigned char bit) { unsigned char val; - spin_lock_irq(&rtc_lock); - if (hpet_mask_rtc_irq_bit(bit)) { - spin_unlock_irq(&rtc_lock); + if (hpet_mask_rtc_irq_bit(bit)) return; - } val = CMOS_READ(RTC_CONTROL); val &= ~bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); rtc_irq_data = 0; - spin_unlock_irq(&rtc_lock); } -static void set_rtc_irq_bit(unsigned char bit) +static void set_rtc_irq_bit_locked(unsigned char bit) { unsigned char val; - spin_lock_irq(&rtc_lock); - if (hpet_set_rtc_irq_bit(bit)) { - spin_unlock_irq(&rtc_lock); + if (hpet_set_rtc_irq_bit(bit)) return; - } val = CMOS_READ(RTC_CONTROL); val |= bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); rtc_irq_data = 0; - spin_unlock_irq(&rtc_lock); } #endif - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |