diff options
Diffstat (limited to 'sound/drivers')
-rw-r--r-- | sound/drivers/Kconfig | 2 | ||||
-rw-r--r-- | sound/drivers/dummy.c | 2 | ||||
-rw-r--r-- | sound/drivers/ml403-ac97cr.c | 4 | ||||
-rw-r--r-- | sound/drivers/pcsp/pcsp.c | 8 | ||||
-rw-r--r-- | sound/drivers/pcsp/pcsp.h | 3 | ||||
-rw-r--r-- | sound/drivers/pcsp/pcsp_input.c | 4 | ||||
-rw-r--r-- | sound/drivers/pcsp/pcsp_lib.c | 167 | ||||
-rw-r--r-- | sound/drivers/vx/vx_core.c | 2 | ||||
-rw-r--r-- | sound/drivers/vx/vx_pcm.c | 2 |
9 files changed, 115 insertions, 79 deletions
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 255fd18b9aec..0bcf14640fde 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -163,7 +163,7 @@ config SND_ML403_AC97CR | |||
163 | 163 | ||
164 | config SND_AC97_POWER_SAVE | 164 | config SND_AC97_POWER_SAVE |
165 | bool "AC97 Power-Saving Mode" | 165 | bool "AC97 Power-Saving Mode" |
166 | depends on SND_AC97_CODEC && EXPERIMENTAL | 166 | depends on SND_AC97_CODEC |
167 | default n | 167 | default n |
168 | help | 168 | help |
169 | Say Y here to enable the aggressive power-saving support of | 169 | Say Y here to enable the aggressive power-saving support of |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index e5e749f3e0ef..73be7e14a603 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -51,7 +51,7 @@ static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) | |||
51 | if (err < 0) | 51 | if (err < 0) |
52 | return err; | 52 | return err; |
53 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); | 53 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); |
54 | if (err) < 0) | 54 | if (err < 0) |
55 | return err; | 55 | return err; |
56 | return 0; | 56 | return 0; |
57 | } | 57 | } |
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c index ecdbeb6d3603..7783843ca9ae 100644 --- a/sound/drivers/ml403-ac97cr.c +++ b/sound/drivers/ml403-ac97cr.c | |||
@@ -1153,7 +1153,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, | |||
1153 | /* get irq */ | 1153 | /* get irq */ |
1154 | irq = platform_get_irq(pfdev, 0); | 1154 | irq = platform_get_irq(pfdev, 0); |
1155 | if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, | 1155 | if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, |
1156 | pfdev->dev.bus_id, (void *)ml403_ac97cr)) { | 1156 | dev_name(&pfdev->dev), (void *)ml403_ac97cr)) { |
1157 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | 1157 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " |
1158 | "unable to grab IRQ %d\n", | 1158 | "unable to grab IRQ %d\n", |
1159 | irq); | 1159 | irq); |
@@ -1166,7 +1166,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, | |||
1166 | ml403_ac97cr->irq); | 1166 | ml403_ac97cr->irq); |
1167 | irq = platform_get_irq(pfdev, 1); | 1167 | irq = platform_get_irq(pfdev, 1); |
1168 | if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, | 1168 | if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, |
1169 | pfdev->dev.bus_id, (void *)ml403_ac97cr)) { | 1169 | dev_name(&pfdev->dev), (void *)ml403_ac97cr)) { |
1170 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | 1170 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " |
1171 | "unable to grab IRQ %d\n", | 1171 | "unable to grab IRQ %d\n", |
1172 | irq); | 1172 | irq); |
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index 1899cf0685bc..2a02f704f366 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c | |||
@@ -96,7 +96,7 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) | |||
96 | return -EINVAL; | 96 | return -EINVAL; |
97 | 97 | ||
98 | hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 98 | hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
99 | pcsp_chip.timer.cb_mode = HRTIMER_CB_SOFTIRQ; | 99 | pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED; |
100 | pcsp_chip.timer.function = pcsp_do_timer; | 100 | pcsp_chip.timer.function = pcsp_do_timer; |
101 | 101 | ||
102 | card = snd_card_new(index, id, THIS_MODULE, 0); | 102 | card = snd_card_new(index, id, THIS_MODULE, 0); |
@@ -188,10 +188,8 @@ static int __devexit pcsp_remove(struct platform_device *dev) | |||
188 | 188 | ||
189 | static void pcsp_stop_beep(struct snd_pcsp *chip) | 189 | static void pcsp_stop_beep(struct snd_pcsp *chip) |
190 | { | 190 | { |
191 | spin_lock_irq(&chip->substream_lock); | 191 | pcsp_sync_stop(chip); |
192 | if (!chip->playback_substream) | 192 | pcspkr_stop_sound(); |
193 | pcspkr_stop_sound(); | ||
194 | spin_unlock_irq(&chip->substream_lock); | ||
195 | } | 193 | } |
196 | 194 | ||
197 | #ifdef CONFIG_PM | 195 | #ifdef CONFIG_PM |
diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h index 1d661f795e8c..cdef2664218f 100644 --- a/sound/drivers/pcsp/pcsp.h +++ b/sound/drivers/pcsp/pcsp.h | |||
@@ -62,6 +62,8 @@ struct snd_pcsp { | |||
62 | unsigned short port, irq, dma; | 62 | unsigned short port, irq, dma; |
63 | spinlock_t substream_lock; | 63 | spinlock_t substream_lock; |
64 | struct snd_pcm_substream *playback_substream; | 64 | struct snd_pcm_substream *playback_substream; |
65 | unsigned int fmt_size; | ||
66 | unsigned int is_signed; | ||
65 | size_t playback_ptr; | 67 | size_t playback_ptr; |
66 | size_t period_ptr; | 68 | size_t period_ptr; |
67 | atomic_t timer_active; | 69 | atomic_t timer_active; |
@@ -77,6 +79,7 @@ struct snd_pcsp { | |||
77 | extern struct snd_pcsp pcsp_chip; | 79 | extern struct snd_pcsp pcsp_chip; |
78 | 80 | ||
79 | extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle); | 81 | extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle); |
82 | extern void pcsp_sync_stop(struct snd_pcsp *chip); | ||
80 | 83 | ||
81 | extern int snd_pcsp_new_pcm(struct snd_pcsp *chip); | 84 | extern int snd_pcsp_new_pcm(struct snd_pcsp *chip); |
82 | extern int snd_pcsp_new_mixer(struct snd_pcsp *chip); | 85 | extern int snd_pcsp_new_mixer(struct snd_pcsp *chip); |
diff --git a/sound/drivers/pcsp/pcsp_input.c b/sound/drivers/pcsp/pcsp_input.c index cd9b83e7f7d1..0444cdeb4bec 100644 --- a/sound/drivers/pcsp/pcsp_input.c +++ b/sound/drivers/pcsp/pcsp_input.c | |||
@@ -24,13 +24,13 @@ static void pcspkr_do_sound(unsigned int count) | |||
24 | spin_lock_irqsave(&i8253_lock, flags); | 24 | spin_lock_irqsave(&i8253_lock, flags); |
25 | 25 | ||
26 | if (count) { | 26 | if (count) { |
27 | /* enable counter 2 */ | ||
28 | outb_p(inb_p(0x61) | 3, 0x61); | ||
29 | /* set command for counter 2, 2 byte write */ | 27 | /* set command for counter 2, 2 byte write */ |
30 | outb_p(0xB6, 0x43); | 28 | outb_p(0xB6, 0x43); |
31 | /* select desired HZ */ | 29 | /* select desired HZ */ |
32 | outb_p(count & 0xff, 0x42); | 30 | outb_p(count & 0xff, 0x42); |
33 | outb((count >> 8) & 0xff, 0x42); | 31 | outb((count >> 8) & 0xff, 0x42); |
32 | /* enable counter 2 */ | ||
33 | outb_p(inb_p(0x61) | 3, 0x61); | ||
34 | } else { | 34 | } else { |
35 | /* disable counter 2 */ | 35 | /* disable counter 2 */ |
36 | outb(inb_p(0x61) & 0xFC, 0x61); | 36 | outb(inb_p(0x61) & 0xFC, 0x61); |
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index e341f3f83b6a..84cc2658c05b 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/moduleparam.h> | 10 | #include <linux/moduleparam.h> |
11 | #include <linux/interrupt.h> | ||
11 | #include <sound/pcm.h> | 12 | #include <sound/pcm.h> |
12 | #include <asm/io.h> | 13 | #include <asm/io.h> |
13 | #include "pcsp.h" | 14 | #include "pcsp.h" |
@@ -19,61 +20,57 @@ MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround " | |||
19 | 20 | ||
20 | #define DMIX_WANTS_S16 1 | 21 | #define DMIX_WANTS_S16 1 |
21 | 22 | ||
22 | enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) | 23 | /* |
24 | * Call snd_pcm_period_elapsed in a tasklet | ||
25 | * This avoids spinlock messes and long-running irq contexts | ||
26 | */ | ||
27 | static void pcsp_call_pcm_elapsed(unsigned long priv) | ||
28 | { | ||
29 | if (atomic_read(&pcsp_chip.timer_active)) { | ||
30 | struct snd_pcm_substream *substream; | ||
31 | substream = pcsp_chip.playback_substream; | ||
32 | if (substream) | ||
33 | snd_pcm_period_elapsed(substream); | ||
34 | } | ||
35 | } | ||
36 | |||
37 | static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); | ||
38 | |||
39 | /* write the port and returns the next expire time in ns; | ||
40 | * called at the trigger-start and in hrtimer callback | ||
41 | */ | ||
42 | static unsigned long pcsp_timer_update(struct hrtimer *handle) | ||
23 | { | 43 | { |
24 | unsigned char timer_cnt, val; | 44 | unsigned char timer_cnt, val; |
25 | int fmt_size, periods_elapsed; | ||
26 | u64 ns; | 45 | u64 ns; |
27 | size_t period_bytes, buffer_bytes; | ||
28 | struct snd_pcm_substream *substream; | 46 | struct snd_pcm_substream *substream; |
29 | struct snd_pcm_runtime *runtime; | 47 | struct snd_pcm_runtime *runtime; |
30 | struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); | 48 | struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); |
49 | unsigned long flags; | ||
31 | 50 | ||
32 | if (chip->thalf) { | 51 | if (chip->thalf) { |
33 | outb(chip->val61, 0x61); | 52 | outb(chip->val61, 0x61); |
34 | chip->thalf = 0; | 53 | chip->thalf = 0; |
35 | if (!atomic_read(&chip->timer_active)) | 54 | if (!atomic_read(&chip->timer_active)) |
36 | return HRTIMER_NORESTART; | 55 | return 0; |
37 | hrtimer_forward(&chip->timer, chip->timer.expires, | 56 | return chip->ns_rem; |
38 | ktime_set(0, chip->ns_rem)); | ||
39 | return HRTIMER_RESTART; | ||
40 | } | 57 | } |
41 | 58 | ||
42 | spin_lock_irq(&chip->substream_lock); | ||
43 | /* Takashi Iwai says regarding this extra lock: | ||
44 | |||
45 | If the irq handler handles some data on the DMA buffer, it should | ||
46 | do snd_pcm_stream_lock(). | ||
47 | That protects basically against all races among PCM callbacks, yes. | ||
48 | However, there are two remaining issues: | ||
49 | 1. The substream pointer you try to lock isn't protected _before_ | ||
50 | this lock yet. | ||
51 | 2. snd_pcm_period_elapsed() itself acquires the lock. | ||
52 | The requirement of another lock is because of 1. When you get | ||
53 | chip->playback_substream, it's not protected. | ||
54 | Keeping this lock while snd_pcm_period_elapsed() assures the substream | ||
55 | is still protected (at least, not released). And the other status is | ||
56 | handled properly inside snd_pcm_stream_lock() in | ||
57 | snd_pcm_period_elapsed(). | ||
58 | |||
59 | */ | ||
60 | if (!chip->playback_substream) | ||
61 | goto exit_nr_unlock1; | ||
62 | substream = chip->playback_substream; | ||
63 | snd_pcm_stream_lock(substream); | ||
64 | if (!atomic_read(&chip->timer_active)) | 59 | if (!atomic_read(&chip->timer_active)) |
65 | goto exit_nr_unlock2; | 60 | return 0; |
61 | substream = chip->playback_substream; | ||
62 | if (!substream) | ||
63 | return 0; | ||
66 | 64 | ||
67 | runtime = substream->runtime; | 65 | runtime = substream->runtime; |
68 | fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3; | ||
69 | /* assume it is mono! */ | 66 | /* assume it is mono! */ |
70 | val = runtime->dma_area[chip->playback_ptr + fmt_size - 1]; | 67 | val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1]; |
71 | if (snd_pcm_format_signed(runtime->format)) | 68 | if (chip->is_signed) |
72 | val ^= 0x80; | 69 | val ^= 0x80; |
73 | timer_cnt = val * CUR_DIV() / 256; | 70 | timer_cnt = val * CUR_DIV() / 256; |
74 | 71 | ||
75 | if (timer_cnt && chip->enable) { | 72 | if (timer_cnt && chip->enable) { |
76 | spin_lock(&i8253_lock); | 73 | spin_lock_irqsave(&i8253_lock, flags); |
77 | if (!nforce_wa) { | 74 | if (!nforce_wa) { |
78 | outb_p(chip->val61, 0x61); | 75 | outb_p(chip->val61, 0x61); |
79 | outb_p(timer_cnt, 0x42); | 76 | outb_p(timer_cnt, 0x42); |
@@ -82,12 +79,39 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) | |||
82 | outb(chip->val61 ^ 2, 0x61); | 79 | outb(chip->val61 ^ 2, 0x61); |
83 | chip->thalf = 1; | 80 | chip->thalf = 1; |
84 | } | 81 | } |
85 | spin_unlock(&i8253_lock); | 82 | spin_unlock_irqrestore(&i8253_lock, flags); |
86 | } | 83 | } |
87 | 84 | ||
85 | chip->ns_rem = PCSP_PERIOD_NS(); | ||
86 | ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); | ||
87 | chip->ns_rem -= ns; | ||
88 | return ns; | ||
89 | } | ||
90 | |||
91 | enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) | ||
92 | { | ||
93 | struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); | ||
94 | struct snd_pcm_substream *substream; | ||
95 | int periods_elapsed, pointer_update; | ||
96 | size_t period_bytes, buffer_bytes; | ||
97 | unsigned long ns; | ||
98 | unsigned long flags; | ||
99 | |||
100 | pointer_update = !chip->thalf; | ||
101 | ns = pcsp_timer_update(handle); | ||
102 | if (!ns) | ||
103 | return HRTIMER_NORESTART; | ||
104 | |||
105 | /* update the playback position */ | ||
106 | substream = chip->playback_substream; | ||
107 | if (!substream) | ||
108 | return HRTIMER_NORESTART; | ||
109 | |||
88 | period_bytes = snd_pcm_lib_period_bytes(substream); | 110 | period_bytes = snd_pcm_lib_period_bytes(substream); |
89 | buffer_bytes = snd_pcm_lib_buffer_bytes(substream); | 111 | buffer_bytes = snd_pcm_lib_buffer_bytes(substream); |
90 | chip->playback_ptr += PCSP_INDEX_INC() * fmt_size; | 112 | |
113 | spin_lock_irqsave(&chip->substream_lock, flags); | ||
114 | chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size; | ||
91 | periods_elapsed = chip->playback_ptr - chip->period_ptr; | 115 | periods_elapsed = chip->playback_ptr - chip->period_ptr; |
92 | if (periods_elapsed < 0) { | 116 | if (periods_elapsed < 0) { |
93 | #if PCSP_DEBUG | 117 | #if PCSP_DEBUG |
@@ -102,40 +126,30 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) | |||
102 | * or ALSA will BUG on us. */ | 126 | * or ALSA will BUG on us. */ |
103 | chip->playback_ptr %= buffer_bytes; | 127 | chip->playback_ptr %= buffer_bytes; |
104 | 128 | ||
105 | snd_pcm_stream_unlock(substream); | ||
106 | |||
107 | if (periods_elapsed) { | 129 | if (periods_elapsed) { |
108 | snd_pcm_period_elapsed(substream); | ||
109 | chip->period_ptr += periods_elapsed * period_bytes; | 130 | chip->period_ptr += periods_elapsed * period_bytes; |
110 | chip->period_ptr %= buffer_bytes; | 131 | chip->period_ptr %= buffer_bytes; |
111 | } | 132 | } |
133 | spin_unlock_irqrestore(&chip->substream_lock, flags); | ||
112 | 134 | ||
113 | spin_unlock_irq(&chip->substream_lock); | 135 | if (periods_elapsed) |
136 | tasklet_schedule(&pcsp_pcm_tasklet); | ||
114 | 137 | ||
115 | if (!atomic_read(&chip->timer_active)) | 138 | hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns)); |
116 | return HRTIMER_NORESTART; | ||
117 | 139 | ||
118 | chip->ns_rem = PCSP_PERIOD_NS(); | ||
119 | ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); | ||
120 | chip->ns_rem -= ns; | ||
121 | hrtimer_forward(&chip->timer, chip->timer.expires, ktime_set(0, ns)); | ||
122 | return HRTIMER_RESTART; | 140 | return HRTIMER_RESTART; |
123 | |||
124 | exit_nr_unlock2: | ||
125 | snd_pcm_stream_unlock(substream); | ||
126 | exit_nr_unlock1: | ||
127 | spin_unlock_irq(&chip->substream_lock); | ||
128 | return HRTIMER_NORESTART; | ||
129 | } | 141 | } |
130 | 142 | ||
131 | static void pcsp_start_playing(struct snd_pcsp *chip) | 143 | static int pcsp_start_playing(struct snd_pcsp *chip) |
132 | { | 144 | { |
145 | unsigned long ns; | ||
146 | |||
133 | #if PCSP_DEBUG | 147 | #if PCSP_DEBUG |
134 | printk(KERN_INFO "PCSP: start_playing called\n"); | 148 | printk(KERN_INFO "PCSP: start_playing called\n"); |
135 | #endif | 149 | #endif |
136 | if (atomic_read(&chip->timer_active)) { | 150 | if (atomic_read(&chip->timer_active)) { |
137 | printk(KERN_ERR "PCSP: Timer already active\n"); | 151 | printk(KERN_ERR "PCSP: Timer already active\n"); |
138 | return; | 152 | return -EIO; |
139 | } | 153 | } |
140 | 154 | ||
141 | spin_lock(&i8253_lock); | 155 | spin_lock(&i8253_lock); |
@@ -145,7 +159,12 @@ static void pcsp_start_playing(struct snd_pcsp *chip) | |||
145 | atomic_set(&chip->timer_active, 1); | 159 | atomic_set(&chip->timer_active, 1); |
146 | chip->thalf = 0; | 160 | chip->thalf = 0; |
147 | 161 | ||
148 | hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL); | 162 | ns = pcsp_timer_update(&pcsp_chip.timer); |
163 | if (!ns) | ||
164 | return -EIO; | ||
165 | |||
166 | hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL); | ||
167 | return 0; | ||
149 | } | 168 | } |
150 | 169 | ||
151 | static void pcsp_stop_playing(struct snd_pcsp *chip) | 170 | static void pcsp_stop_playing(struct snd_pcsp *chip) |
@@ -164,26 +183,35 @@ static void pcsp_stop_playing(struct snd_pcsp *chip) | |||
164 | spin_unlock(&i8253_lock); | 183 | spin_unlock(&i8253_lock); |
165 | } | 184 | } |
166 | 185 | ||
186 | /* | ||
187 | * Force to stop and sync the stream | ||
188 | */ | ||
189 | void pcsp_sync_stop(struct snd_pcsp *chip) | ||
190 | { | ||
191 | local_irq_disable(); | ||
192 | pcsp_stop_playing(chip); | ||
193 | local_irq_enable(); | ||
194 | hrtimer_cancel(&chip->timer); | ||
195 | tasklet_kill(&pcsp_pcm_tasklet); | ||
196 | } | ||
197 | |||
167 | static int snd_pcsp_playback_close(struct snd_pcm_substream *substream) | 198 | static int snd_pcsp_playback_close(struct snd_pcm_substream *substream) |
168 | { | 199 | { |
169 | struct snd_pcsp *chip = snd_pcm_substream_chip(substream); | 200 | struct snd_pcsp *chip = snd_pcm_substream_chip(substream); |
170 | #if PCSP_DEBUG | 201 | #if PCSP_DEBUG |
171 | printk(KERN_INFO "PCSP: close called\n"); | 202 | printk(KERN_INFO "PCSP: close called\n"); |
172 | #endif | 203 | #endif |
173 | if (atomic_read(&chip->timer_active)) { | 204 | pcsp_sync_stop(chip); |
174 | printk(KERN_ERR "PCSP: timer still active\n"); | ||
175 | pcsp_stop_playing(chip); | ||
176 | } | ||
177 | spin_lock_irq(&chip->substream_lock); | ||
178 | chip->playback_substream = NULL; | 205 | chip->playback_substream = NULL; |
179 | spin_unlock_irq(&chip->substream_lock); | ||
180 | return 0; | 206 | return 0; |
181 | } | 207 | } |
182 | 208 | ||
183 | static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream, | 209 | static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream, |
184 | struct snd_pcm_hw_params *hw_params) | 210 | struct snd_pcm_hw_params *hw_params) |
185 | { | 211 | { |
212 | struct snd_pcsp *chip = snd_pcm_substream_chip(substream); | ||
186 | int err; | 213 | int err; |
214 | pcsp_sync_stop(chip); | ||
187 | err = snd_pcm_lib_malloc_pages(substream, | 215 | err = snd_pcm_lib_malloc_pages(substream, |
188 | params_buffer_bytes(hw_params)); | 216 | params_buffer_bytes(hw_params)); |
189 | if (err < 0) | 217 | if (err < 0) |
@@ -193,9 +221,11 @@ static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream, | |||
193 | 221 | ||
194 | static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream) | 222 | static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream) |
195 | { | 223 | { |
224 | struct snd_pcsp *chip = snd_pcm_substream_chip(substream); | ||
196 | #if PCSP_DEBUG | 225 | #if PCSP_DEBUG |
197 | printk(KERN_INFO "PCSP: hw_free called\n"); | 226 | printk(KERN_INFO "PCSP: hw_free called\n"); |
198 | #endif | 227 | #endif |
228 | pcsp_sync_stop(chip); | ||
199 | return snd_pcm_lib_free_pages(substream); | 229 | return snd_pcm_lib_free_pages(substream); |
200 | } | 230 | } |
201 | 231 | ||
@@ -211,8 +241,12 @@ static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream) | |||
211 | snd_pcm_lib_period_bytes(substream), | 241 | snd_pcm_lib_period_bytes(substream), |
212 | substream->runtime->periods); | 242 | substream->runtime->periods); |
213 | #endif | 243 | #endif |
244 | pcsp_sync_stop(chip); | ||
214 | chip->playback_ptr = 0; | 245 | chip->playback_ptr = 0; |
215 | chip->period_ptr = 0; | 246 | chip->period_ptr = 0; |
247 | chip->fmt_size = | ||
248 | snd_pcm_format_physical_width(substream->runtime->format) >> 3; | ||
249 | chip->is_signed = snd_pcm_format_signed(substream->runtime->format); | ||
216 | return 0; | 250 | return 0; |
217 | } | 251 | } |
218 | 252 | ||
@@ -225,8 +259,7 @@ static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd) | |||
225 | switch (cmd) { | 259 | switch (cmd) { |
226 | case SNDRV_PCM_TRIGGER_START: | 260 | case SNDRV_PCM_TRIGGER_START: |
227 | case SNDRV_PCM_TRIGGER_RESUME: | 261 | case SNDRV_PCM_TRIGGER_RESUME: |
228 | pcsp_start_playing(chip); | 262 | return pcsp_start_playing(chip); |
229 | break; | ||
230 | case SNDRV_PCM_TRIGGER_STOP: | 263 | case SNDRV_PCM_TRIGGER_STOP: |
231 | case SNDRV_PCM_TRIGGER_SUSPEND: | 264 | case SNDRV_PCM_TRIGGER_SUSPEND: |
232 | pcsp_stop_playing(chip); | 265 | pcsp_stop_playing(chip); |
@@ -241,7 +274,11 @@ static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream | |||
241 | *substream) | 274 | *substream) |
242 | { | 275 | { |
243 | struct snd_pcsp *chip = snd_pcm_substream_chip(substream); | 276 | struct snd_pcsp *chip = snd_pcm_substream_chip(substream); |
244 | return bytes_to_frames(substream->runtime, chip->playback_ptr); | 277 | unsigned int pos; |
278 | spin_lock(&chip->substream_lock); | ||
279 | pos = chip->playback_ptr; | ||
280 | spin_unlock(&chip->substream_lock); | ||
281 | return bytes_to_frames(substream->runtime, pos); | ||
245 | } | 282 | } |
246 | 283 | ||
247 | static struct snd_pcm_hardware snd_pcsp_playback = { | 284 | static struct snd_pcm_hardware snd_pcsp_playback = { |
@@ -278,9 +315,7 @@ static int snd_pcsp_playback_open(struct snd_pcm_substream *substream) | |||
278 | return -EBUSY; | 315 | return -EBUSY; |
279 | } | 316 | } |
280 | runtime->hw = snd_pcsp_playback; | 317 | runtime->hw = snd_pcsp_playback; |
281 | spin_lock_irq(&chip->substream_lock); | ||
282 | chip->playback_substream = substream; | 318 | chip->playback_substream = substream; |
283 | spin_unlock_irq(&chip->substream_lock); | ||
284 | return 0; | 319 | return 0; |
285 | } | 320 | } |
286 | 321 | ||
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 473b07f6ae85..14e3354be43a 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c | |||
@@ -548,7 +548,7 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev) | |||
548 | (chip->chip_status & VX_STAT_IS_STALE)) | 548 | (chip->chip_status & VX_STAT_IS_STALE)) |
549 | return IRQ_NONE; | 549 | return IRQ_NONE; |
550 | if (! vx_test_and_ack(chip)) | 550 | if (! vx_test_and_ack(chip)) |
551 | tasklet_hi_schedule(&chip->tq); | 551 | tasklet_schedule(&chip->tq); |
552 | return IRQ_HANDLED; | 552 | return IRQ_HANDLED; |
553 | } | 553 | } |
554 | 554 | ||
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 27de574c08f7..6644d0034fba 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c | |||
@@ -823,7 +823,7 @@ static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd) | |||
823 | * we trigger the pipe using tasklet, so that the interrupts are | 823 | * we trigger the pipe using tasklet, so that the interrupts are |
824 | * issued surely after the trigger is completed. | 824 | * issued surely after the trigger is completed. |
825 | */ | 825 | */ |
826 | tasklet_hi_schedule(&pipe->start_tq); | 826 | tasklet_schedule(&pipe->start_tq); |
827 | chip->pcm_running++; | 827 | chip->pcm_running++; |
828 | pipe->running = 1; | 828 | pipe->running = 1; |
829 | break; | 829 | break; |