diff options
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/hwdep.c | 9 | ||||
-rw-r--r-- | sound/core/init.c | 89 | ||||
-rw-r--r-- | sound/core/jack.c | 45 | ||||
-rw-r--r-- | sound/core/misc.c | 10 | ||||
-rw-r--r-- | sound/core/oss/pcm_oss.c | 49 | ||||
-rw-r--r-- | sound/core/oss/pcm_plugin.h | 4 | ||||
-rw-r--r-- | sound/core/pcm.c | 3 | ||||
-rw-r--r-- | sound/core/pcm_lib.c | 155 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 6 | ||||
-rw-r--r-- | sound/core/pcm_timer.c | 6 | ||||
-rw-r--r-- | sound/core/rawmidi.c | 379 | ||||
-rw-r--r-- | sound/core/seq/oss/seq_oss_device.h | 2 | ||||
-rw-r--r-- | sound/core/seq/seq_prioq.c | 3 | ||||
-rw-r--r-- | sound/core/vmaster.c | 62 |
14 files changed, 458 insertions, 364 deletions
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 195cafc5a553..a70ee7f1ed98 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
@@ -99,9 +99,6 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) | |||
99 | if (hw == NULL) | 99 | if (hw == NULL) |
100 | return -ENODEV; | 100 | return -ENODEV; |
101 | 101 | ||
102 | if (!hw->ops.open) | ||
103 | return -ENXIO; | ||
104 | |||
105 | if (!try_module_get(hw->card->module)) | 102 | if (!try_module_get(hw->card->module)) |
106 | return -EFAULT; | 103 | return -EFAULT; |
107 | 104 | ||
@@ -113,6 +110,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) | |||
113 | err = -EBUSY; | 110 | err = -EBUSY; |
114 | break; | 111 | break; |
115 | } | 112 | } |
113 | if (!hw->ops.open) { | ||
114 | err = 0; | ||
115 | break; | ||
116 | } | ||
116 | err = hw->ops.open(hw, file); | 117 | err = hw->ops.open(hw, file); |
117 | if (err >= 0) | 118 | if (err >= 0) |
118 | break; | 119 | break; |
@@ -151,7 +152,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) | |||
151 | 152 | ||
152 | static int snd_hwdep_release(struct inode *inode, struct file * file) | 153 | static int snd_hwdep_release(struct inode *inode, struct file * file) |
153 | { | 154 | { |
154 | int err = -ENXIO; | 155 | int err = 0; |
155 | struct snd_hwdep *hw = file->private_data; | 156 | struct snd_hwdep *hw = file->private_data; |
156 | struct module *mod = hw->card->module; | 157 | struct module *mod = hw->card->module; |
157 | 158 | ||
diff --git a/sound/core/init.c b/sound/core/init.c index 0d5520c415d3..fd56afe846ed 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -121,31 +121,44 @@ static inline int init_info_for_card(struct snd_card *card) | |||
121 | #endif | 121 | #endif |
122 | 122 | ||
123 | /** | 123 | /** |
124 | * snd_card_new - create and initialize a soundcard structure | 124 | * snd_card_create - create and initialize a soundcard structure |
125 | * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] | 125 | * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] |
126 | * @xid: card identification (ASCII string) | 126 | * @xid: card identification (ASCII string) |
127 | * @module: top level module for locking | 127 | * @module: top level module for locking |
128 | * @extra_size: allocate this extra size after the main soundcard structure | 128 | * @extra_size: allocate this extra size after the main soundcard structure |
129 | * @card_ret: the pointer to store the created card instance | ||
129 | * | 130 | * |
130 | * Creates and initializes a soundcard structure. | 131 | * Creates and initializes a soundcard structure. |
131 | * | 132 | * |
132 | * Returns kmallocated snd_card structure. Creates the ALSA control interface | 133 | * The function allocates snd_card instance via kzalloc with the given |
133 | * (which is blocked until snd_card_register function is called). | 134 | * space for the driver to use freely. The allocated struct is stored |
135 | * in the given card_ret pointer. | ||
136 | * | ||
137 | * Returns zero if successful or a negative error code. | ||
134 | */ | 138 | */ |
135 | struct snd_card *snd_card_new(int idx, const char *xid, | 139 | int snd_card_create(int idx, const char *xid, |
136 | struct module *module, int extra_size) | 140 | struct module *module, int extra_size, |
141 | struct snd_card **card_ret) | ||
137 | { | 142 | { |
138 | struct snd_card *card; | 143 | struct snd_card *card; |
139 | int err, idx2; | 144 | int err, idx2; |
140 | 145 | ||
146 | if (snd_BUG_ON(!card_ret)) | ||
147 | return -EINVAL; | ||
148 | *card_ret = NULL; | ||
149 | |||
141 | if (extra_size < 0) | 150 | if (extra_size < 0) |
142 | extra_size = 0; | 151 | extra_size = 0; |
143 | card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); | 152 | card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); |
144 | if (card == NULL) | 153 | if (!card) |
145 | return NULL; | 154 | return -ENOMEM; |
146 | if (xid) { | 155 | if (xid) { |
147 | if (!snd_info_check_reserved_words(xid)) | 156 | if (!snd_info_check_reserved_words(xid)) { |
157 | snd_printk(KERN_ERR | ||
158 | "given id string '%s' is reserved.\n", xid); | ||
159 | err = -EBUSY; | ||
148 | goto __error; | 160 | goto __error; |
161 | } | ||
149 | strlcpy(card->id, xid, sizeof(card->id)); | 162 | strlcpy(card->id, xid, sizeof(card->id)); |
150 | } | 163 | } |
151 | err = 0; | 164 | err = 0; |
@@ -195,6 +208,7 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
195 | INIT_LIST_HEAD(&card->controls); | 208 | INIT_LIST_HEAD(&card->controls); |
196 | INIT_LIST_HEAD(&card->ctl_files); | 209 | INIT_LIST_HEAD(&card->ctl_files); |
197 | spin_lock_init(&card->files_lock); | 210 | spin_lock_init(&card->files_lock); |
211 | INIT_LIST_HEAD(&card->files_list); | ||
198 | init_waitqueue_head(&card->shutdown_sleep); | 212 | init_waitqueue_head(&card->shutdown_sleep); |
199 | #ifdef CONFIG_PM | 213 | #ifdef CONFIG_PM |
200 | mutex_init(&card->power_lock); | 214 | mutex_init(&card->power_lock); |
@@ -202,26 +216,28 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
202 | #endif | 216 | #endif |
203 | /* the control interface cannot be accessed from the user space until */ | 217 | /* the control interface cannot be accessed from the user space until */ |
204 | /* snd_cards_bitmask and snd_cards are set with snd_card_register */ | 218 | /* snd_cards_bitmask and snd_cards are set with snd_card_register */ |
205 | if ((err = snd_ctl_create(card)) < 0) { | 219 | err = snd_ctl_create(card); |
206 | snd_printd("unable to register control minors\n"); | 220 | if (err < 0) { |
221 | snd_printk(KERN_ERR "unable to register control minors\n"); | ||
207 | goto __error; | 222 | goto __error; |
208 | } | 223 | } |
209 | if ((err = snd_info_card_create(card)) < 0) { | 224 | err = snd_info_card_create(card); |
210 | snd_printd("unable to create card info\n"); | 225 | if (err < 0) { |
226 | snd_printk(KERN_ERR "unable to create card info\n"); | ||
211 | goto __error_ctl; | 227 | goto __error_ctl; |
212 | } | 228 | } |
213 | if (extra_size > 0) | 229 | if (extra_size > 0) |
214 | card->private_data = (char *)card + sizeof(struct snd_card); | 230 | card->private_data = (char *)card + sizeof(struct snd_card); |
215 | return card; | 231 | *card_ret = card; |
232 | return 0; | ||
216 | 233 | ||
217 | __error_ctl: | 234 | __error_ctl: |
218 | snd_device_free_all(card, SNDRV_DEV_CMD_PRE); | 235 | snd_device_free_all(card, SNDRV_DEV_CMD_PRE); |
219 | __error: | 236 | __error: |
220 | kfree(card); | 237 | kfree(card); |
221 | return NULL; | 238 | return err; |
222 | } | 239 | } |
223 | 240 | EXPORT_SYMBOL(snd_card_create); | |
224 | EXPORT_SYMBOL(snd_card_new); | ||
225 | 241 | ||
226 | /* return non-zero if a card is already locked */ | 242 | /* return non-zero if a card is already locked */ |
227 | int snd_card_locked(int card) | 243 | int snd_card_locked(int card) |
@@ -259,6 +275,7 @@ static int snd_disconnect_release(struct inode *inode, struct file *file) | |||
259 | list_for_each_entry(_df, &shutdown_files, shutdown_list) { | 275 | list_for_each_entry(_df, &shutdown_files, shutdown_list) { |
260 | if (_df->file == file) { | 276 | if (_df->file == file) { |
261 | df = _df; | 277 | df = _df; |
278 | list_del_init(&df->shutdown_list); | ||
262 | break; | 279 | break; |
263 | } | 280 | } |
264 | } | 281 | } |
@@ -347,8 +364,7 @@ int snd_card_disconnect(struct snd_card *card) | |||
347 | /* phase 2: replace file->f_op with special dummy operations */ | 364 | /* phase 2: replace file->f_op with special dummy operations */ |
348 | 365 | ||
349 | spin_lock(&card->files_lock); | 366 | spin_lock(&card->files_lock); |
350 | mfile = card->files; | 367 | list_for_each_entry(mfile, &card->files_list, list) { |
351 | while (mfile) { | ||
352 | file = mfile->file; | 368 | file = mfile->file; |
353 | 369 | ||
354 | /* it's critical part, use endless loop */ | 370 | /* it's critical part, use endless loop */ |
@@ -361,8 +377,6 @@ int snd_card_disconnect(struct snd_card *card) | |||
361 | 377 | ||
362 | mfile->file->f_op = &snd_shutdown_f_ops; | 378 | mfile->file->f_op = &snd_shutdown_f_ops; |
363 | fops_get(mfile->file->f_op); | 379 | fops_get(mfile->file->f_op); |
364 | |||
365 | mfile = mfile->next; | ||
366 | } | 380 | } |
367 | spin_unlock(&card->files_lock); | 381 | spin_unlock(&card->files_lock); |
368 | 382 | ||
@@ -442,7 +456,7 @@ int snd_card_free_when_closed(struct snd_card *card) | |||
442 | return ret; | 456 | return ret; |
443 | 457 | ||
444 | spin_lock(&card->files_lock); | 458 | spin_lock(&card->files_lock); |
445 | if (card->files == NULL) | 459 | if (list_empty(&card->files_list)) |
446 | free_now = 1; | 460 | free_now = 1; |
447 | else | 461 | else |
448 | card->free_on_last_close = 1; | 462 | card->free_on_last_close = 1; |
@@ -462,7 +476,7 @@ int snd_card_free(struct snd_card *card) | |||
462 | return ret; | 476 | return ret; |
463 | 477 | ||
464 | /* wait, until all devices are ready for the free operation */ | 478 | /* wait, until all devices are ready for the free operation */ |
465 | wait_event(card->shutdown_sleep, card->files == NULL); | 479 | wait_event(card->shutdown_sleep, list_empty(&card->files_list)); |
466 | snd_card_do_free(card); | 480 | snd_card_do_free(card); |
467 | return 0; | 481 | return 0; |
468 | } | 482 | } |
@@ -809,15 +823,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file) | |||
809 | return -ENOMEM; | 823 | return -ENOMEM; |
810 | mfile->file = file; | 824 | mfile->file = file; |
811 | mfile->disconnected_f_op = NULL; | 825 | mfile->disconnected_f_op = NULL; |
812 | mfile->next = NULL; | ||
813 | spin_lock(&card->files_lock); | 826 | spin_lock(&card->files_lock); |
814 | if (card->shutdown) { | 827 | if (card->shutdown) { |
815 | spin_unlock(&card->files_lock); | 828 | spin_unlock(&card->files_lock); |
816 | kfree(mfile); | 829 | kfree(mfile); |
817 | return -ENODEV; | 830 | return -ENODEV; |
818 | } | 831 | } |
819 | mfile->next = card->files; | 832 | list_add(&mfile->list, &card->files_list); |
820 | card->files = mfile; | ||
821 | spin_unlock(&card->files_lock); | 833 | spin_unlock(&card->files_lock); |
822 | return 0; | 834 | return 0; |
823 | } | 835 | } |
@@ -839,29 +851,20 @@ EXPORT_SYMBOL(snd_card_file_add); | |||
839 | */ | 851 | */ |
840 | int snd_card_file_remove(struct snd_card *card, struct file *file) | 852 | int snd_card_file_remove(struct snd_card *card, struct file *file) |
841 | { | 853 | { |
842 | struct snd_monitor_file *mfile, *pfile = NULL; | 854 | struct snd_monitor_file *mfile, *found = NULL; |
843 | int last_close = 0; | 855 | int last_close = 0; |
844 | 856 | ||
845 | spin_lock(&card->files_lock); | 857 | spin_lock(&card->files_lock); |
846 | mfile = card->files; | 858 | list_for_each_entry(mfile, &card->files_list, list) { |
847 | while (mfile) { | ||
848 | if (mfile->file == file) { | 859 | if (mfile->file == file) { |
849 | if (pfile) | 860 | list_del(&mfile->list); |
850 | pfile->next = mfile->next; | 861 | if (mfile->disconnected_f_op) |
851 | else | 862 | fops_put(mfile->disconnected_f_op); |
852 | card->files = mfile->next; | 863 | found = mfile; |
853 | break; | 864 | break; |
854 | } | 865 | } |
855 | pfile = mfile; | ||
856 | mfile = mfile->next; | ||
857 | } | ||
858 | if (mfile && mfile->disconnected_f_op) { | ||
859 | fops_put(mfile->disconnected_f_op); | ||
860 | spin_lock(&shutdown_lock); | ||
861 | list_del(&mfile->shutdown_list); | ||
862 | spin_unlock(&shutdown_lock); | ||
863 | } | 866 | } |
864 | if (card->files == NULL) | 867 | if (list_empty(&card->files_list)) |
865 | last_close = 1; | 868 | last_close = 1; |
866 | spin_unlock(&card->files_lock); | 869 | spin_unlock(&card->files_lock); |
867 | if (last_close) { | 870 | if (last_close) { |
@@ -869,11 +872,11 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) | |||
869 | if (card->free_on_last_close) | 872 | if (card->free_on_last_close) |
870 | snd_card_do_free(card); | 873 | snd_card_do_free(card); |
871 | } | 874 | } |
872 | if (!mfile) { | 875 | if (!found) { |
873 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); | 876 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); |
874 | return -ENOENT; | 877 | return -ENOENT; |
875 | } | 878 | } |
876 | kfree(mfile); | 879 | kfree(found); |
877 | return 0; | 880 | return 0; |
878 | } | 881 | } |
879 | 882 | ||
diff --git a/sound/core/jack.c b/sound/core/jack.c index 077a85262c1c..c8254c667c62 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c | |||
@@ -23,6 +23,14 @@ | |||
23 | #include <sound/jack.h> | 23 | #include <sound/jack.h> |
24 | #include <sound/core.h> | 24 | #include <sound/core.h> |
25 | 25 | ||
26 | static int jack_types[] = { | ||
27 | SW_HEADPHONE_INSERT, | ||
28 | SW_MICROPHONE_INSERT, | ||
29 | SW_LINEOUT_INSERT, | ||
30 | SW_JACK_PHYSICAL_INSERT, | ||
31 | SW_VIDEOOUT_INSERT, | ||
32 | }; | ||
33 | |||
26 | static int snd_jack_dev_free(struct snd_device *device) | 34 | static int snd_jack_dev_free(struct snd_device *device) |
27 | { | 35 | { |
28 | struct snd_jack *jack = device->device_data; | 36 | struct snd_jack *jack = device->device_data; |
@@ -79,6 +87,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, | |||
79 | { | 87 | { |
80 | struct snd_jack *jack; | 88 | struct snd_jack *jack; |
81 | int err; | 89 | int err; |
90 | int i; | ||
82 | static struct snd_device_ops ops = { | 91 | static struct snd_device_ops ops = { |
83 | .dev_free = snd_jack_dev_free, | 92 | .dev_free = snd_jack_dev_free, |
84 | .dev_register = snd_jack_dev_register, | 93 | .dev_register = snd_jack_dev_register, |
@@ -100,18 +109,10 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, | |||
100 | 109 | ||
101 | jack->type = type; | 110 | jack->type = type; |
102 | 111 | ||
103 | if (type & SND_JACK_HEADPHONE) | 112 | for (i = 0; i < ARRAY_SIZE(jack_types); i++) |
104 | input_set_capability(jack->input_dev, EV_SW, | 113 | if (type & (1 << i)) |
105 | SW_HEADPHONE_INSERT); | 114 | input_set_capability(jack->input_dev, EV_SW, |
106 | if (type & SND_JACK_LINEOUT) | 115 | jack_types[i]); |
107 | input_set_capability(jack->input_dev, EV_SW, | ||
108 | SW_LINEOUT_INSERT); | ||
109 | if (type & SND_JACK_MICROPHONE) | ||
110 | input_set_capability(jack->input_dev, EV_SW, | ||
111 | SW_MICROPHONE_INSERT); | ||
112 | if (type & SND_JACK_MECHANICAL) | ||
113 | input_set_capability(jack->input_dev, EV_SW, | ||
114 | SW_JACK_PHYSICAL_INSERT); | ||
115 | 116 | ||
116 | err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); | 117 | err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); |
117 | if (err < 0) | 118 | if (err < 0) |
@@ -154,21 +155,17 @@ EXPORT_SYMBOL(snd_jack_set_parent); | |||
154 | */ | 155 | */ |
155 | void snd_jack_report(struct snd_jack *jack, int status) | 156 | void snd_jack_report(struct snd_jack *jack, int status) |
156 | { | 157 | { |
158 | int i; | ||
159 | |||
157 | if (!jack) | 160 | if (!jack) |
158 | return; | 161 | return; |
159 | 162 | ||
160 | if (jack->type & SND_JACK_HEADPHONE) | 163 | for (i = 0; i < ARRAY_SIZE(jack_types); i++) { |
161 | input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, | 164 | int testbit = 1 << i; |
162 | status & SND_JACK_HEADPHONE); | 165 | if (jack->type & testbit) |
163 | if (jack->type & SND_JACK_LINEOUT) | 166 | input_report_switch(jack->input_dev, jack_types[i], |
164 | input_report_switch(jack->input_dev, SW_LINEOUT_INSERT, | 167 | status & testbit); |
165 | status & SND_JACK_LINEOUT); | 168 | } |
166 | if (jack->type & SND_JACK_MICROPHONE) | ||
167 | input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, | ||
168 | status & SND_JACK_MICROPHONE); | ||
169 | if (jack->type & SND_JACK_MECHANICAL) | ||
170 | input_report_switch(jack->input_dev, SW_JACK_PHYSICAL_INSERT, | ||
171 | status & SND_JACK_MECHANICAL); | ||
172 | 169 | ||
173 | input_sync(jack->input_dev); | 170 | input_sync(jack->input_dev); |
174 | } | 171 | } |
diff --git a/sound/core/misc.c b/sound/core/misc.c index 38524f615d94..a9710e0c97af 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c | |||
@@ -95,12 +95,14 @@ snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) | |||
95 | { | 95 | { |
96 | const struct snd_pci_quirk *q; | 96 | const struct snd_pci_quirk *q; |
97 | 97 | ||
98 | for (q = list; q->subvendor; q++) | 98 | for (q = list; q->subvendor; q++) { |
99 | if (q->subvendor == pci->subsystem_vendor && | 99 | if (q->subvendor != pci->subsystem_vendor) |
100 | (!q->subdevice || q->subdevice == pci->subsystem_device)) | 100 | continue; |
101 | if (!q->subdevice || | ||
102 | (pci->subsystem_device & q->subdevice_mask) == q->subdevice) | ||
101 | return q; | 103 | return q; |
104 | } | ||
102 | return NULL; | 105 | return NULL; |
103 | } | 106 | } |
104 | |||
105 | EXPORT_SYMBOL(snd_pci_quirk_lookup); | 107 | EXPORT_SYMBOL(snd_pci_quirk_lookup); |
106 | #endif | 108 | #endif |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 699d2890535c..2864cefb773c 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -1160,9 +1160,11 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const | |||
1160 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | 1160 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { |
1161 | #ifdef OSS_DEBUG | 1161 | #ifdef OSS_DEBUG |
1162 | if (runtime->status->state == SNDRV_PCM_STATE_XRUN) | 1162 | if (runtime->status->state == SNDRV_PCM_STATE_XRUN) |
1163 | printk("pcm_oss: write: recovering from XRUN\n"); | 1163 | printk(KERN_DEBUG "pcm_oss: write: " |
1164 | "recovering from XRUN\n"); | ||
1164 | else | 1165 | else |
1165 | printk("pcm_oss: write: recovering from SUSPEND\n"); | 1166 | printk(KERN_DEBUG "pcm_oss: write: " |
1167 | "recovering from SUSPEND\n"); | ||
1166 | #endif | 1168 | #endif |
1167 | ret = snd_pcm_oss_prepare(substream); | 1169 | ret = snd_pcm_oss_prepare(substream); |
1168 | if (ret < 0) | 1170 | if (ret < 0) |
@@ -1196,9 +1198,11 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p | |||
1196 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | 1198 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { |
1197 | #ifdef OSS_DEBUG | 1199 | #ifdef OSS_DEBUG |
1198 | if (runtime->status->state == SNDRV_PCM_STATE_XRUN) | 1200 | if (runtime->status->state == SNDRV_PCM_STATE_XRUN) |
1199 | printk("pcm_oss: read: recovering from XRUN\n"); | 1201 | printk(KERN_DEBUG "pcm_oss: read: " |
1202 | "recovering from XRUN\n"); | ||
1200 | else | 1203 | else |
1201 | printk("pcm_oss: read: recovering from SUSPEND\n"); | 1204 | printk(KERN_DEBUG "pcm_oss: read: " |
1205 | "recovering from SUSPEND\n"); | ||
1202 | #endif | 1206 | #endif |
1203 | ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); | 1207 | ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); |
1204 | if (ret < 0) | 1208 | if (ret < 0) |
@@ -1242,9 +1246,11 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void | |||
1242 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | 1246 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { |
1243 | #ifdef OSS_DEBUG | 1247 | #ifdef OSS_DEBUG |
1244 | if (runtime->status->state == SNDRV_PCM_STATE_XRUN) | 1248 | if (runtime->status->state == SNDRV_PCM_STATE_XRUN) |
1245 | printk("pcm_oss: writev: recovering from XRUN\n"); | 1249 | printk(KERN_DEBUG "pcm_oss: writev: " |
1250 | "recovering from XRUN\n"); | ||
1246 | else | 1251 | else |
1247 | printk("pcm_oss: writev: recovering from SUSPEND\n"); | 1252 | printk(KERN_DEBUG "pcm_oss: writev: " |
1253 | "recovering from SUSPEND\n"); | ||
1248 | #endif | 1254 | #endif |
1249 | ret = snd_pcm_oss_prepare(substream); | 1255 | ret = snd_pcm_oss_prepare(substream); |
1250 | if (ret < 0) | 1256 | if (ret < 0) |
@@ -1278,9 +1284,11 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void * | |||
1278 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | 1284 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { |
1279 | #ifdef OSS_DEBUG | 1285 | #ifdef OSS_DEBUG |
1280 | if (runtime->status->state == SNDRV_PCM_STATE_XRUN) | 1286 | if (runtime->status->state == SNDRV_PCM_STATE_XRUN) |
1281 | printk("pcm_oss: readv: recovering from XRUN\n"); | 1287 | printk(KERN_DEBUG "pcm_oss: readv: " |
1288 | "recovering from XRUN\n"); | ||
1282 | else | 1289 | else |
1283 | printk("pcm_oss: readv: recovering from SUSPEND\n"); | 1290 | printk(KERN_DEBUG "pcm_oss: readv: " |
1291 | "recovering from SUSPEND\n"); | ||
1284 | #endif | 1292 | #endif |
1285 | ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); | 1293 | ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); |
1286 | if (ret < 0) | 1294 | if (ret < 0) |
@@ -1533,7 +1541,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size) | |||
1533 | init_waitqueue_entry(&wait, current); | 1541 | init_waitqueue_entry(&wait, current); |
1534 | add_wait_queue(&runtime->sleep, &wait); | 1542 | add_wait_queue(&runtime->sleep, &wait); |
1535 | #ifdef OSS_DEBUG | 1543 | #ifdef OSS_DEBUG |
1536 | printk("sync1: size = %li\n", size); | 1544 | printk(KERN_DEBUG "sync1: size = %li\n", size); |
1537 | #endif | 1545 | #endif |
1538 | while (1) { | 1546 | while (1) { |
1539 | result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1); | 1547 | result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1); |
@@ -1590,7 +1598,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) | |||
1590 | mutex_lock(&runtime->oss.params_lock); | 1598 | mutex_lock(&runtime->oss.params_lock); |
1591 | if (runtime->oss.buffer_used > 0) { | 1599 | if (runtime->oss.buffer_used > 0) { |
1592 | #ifdef OSS_DEBUG | 1600 | #ifdef OSS_DEBUG |
1593 | printk("sync: buffer_used\n"); | 1601 | printk(KERN_DEBUG "sync: buffer_used\n"); |
1594 | #endif | 1602 | #endif |
1595 | size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width; | 1603 | size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width; |
1596 | snd_pcm_format_set_silence(format, | 1604 | snd_pcm_format_set_silence(format, |
@@ -1603,7 +1611,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) | |||
1603 | } | 1611 | } |
1604 | } else if (runtime->oss.period_ptr > 0) { | 1612 | } else if (runtime->oss.period_ptr > 0) { |
1605 | #ifdef OSS_DEBUG | 1613 | #ifdef OSS_DEBUG |
1606 | printk("sync: period_ptr\n"); | 1614 | printk(KERN_DEBUG "sync: period_ptr\n"); |
1607 | #endif | 1615 | #endif |
1608 | size = runtime->oss.period_bytes - runtime->oss.period_ptr; | 1616 | size = runtime->oss.period_bytes - runtime->oss.period_ptr; |
1609 | snd_pcm_format_set_silence(format, | 1617 | snd_pcm_format_set_silence(format, |
@@ -1952,7 +1960,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr | |||
1952 | int err, cmd; | 1960 | int err, cmd; |
1953 | 1961 | ||
1954 | #ifdef OSS_DEBUG | 1962 | #ifdef OSS_DEBUG |
1955 | printk("pcm_oss: trigger = 0x%x\n", trigger); | 1963 | printk(KERN_DEBUG "pcm_oss: trigger = 0x%x\n", trigger); |
1956 | #endif | 1964 | #endif |
1957 | 1965 | ||
1958 | psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; | 1966 | psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
@@ -2170,7 +2178,9 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre | |||
2170 | } | 2178 | } |
2171 | 2179 | ||
2172 | #ifdef OSS_DEBUG | 2180 | #ifdef OSS_DEBUG |
2173 | printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize); | 2181 | printk(KERN_DEBUG "pcm_oss: space: bytes = %i, fragments = %i, " |
2182 | "fragstotal = %i, fragsize = %i\n", | ||
2183 | info.bytes, info.fragments, info.fragstotal, info.fragsize); | ||
2174 | #endif | 2184 | #endif |
2175 | if (copy_to_user(_info, &info, sizeof(info))) | 2185 | if (copy_to_user(_info, &info, sizeof(info))) |
2176 | return -EFAULT; | 2186 | return -EFAULT; |
@@ -2473,7 +2483,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long | |||
2473 | if (((cmd >> 8) & 0xff) != 'P') | 2483 | if (((cmd >> 8) & 0xff) != 'P') |
2474 | return -EINVAL; | 2484 | return -EINVAL; |
2475 | #ifdef OSS_DEBUG | 2485 | #ifdef OSS_DEBUG |
2476 | printk("pcm_oss: ioctl = 0x%x\n", cmd); | 2486 | printk(KERN_DEBUG "pcm_oss: ioctl = 0x%x\n", cmd); |
2477 | #endif | 2487 | #endif |
2478 | switch (cmd) { | 2488 | switch (cmd) { |
2479 | case SNDCTL_DSP_RESET: | 2489 | case SNDCTL_DSP_RESET: |
@@ -2627,7 +2637,8 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun | |||
2627 | #else | 2637 | #else |
2628 | { | 2638 | { |
2629 | ssize_t res = snd_pcm_oss_read1(substream, buf, count); | 2639 | ssize_t res = snd_pcm_oss_read1(substream, buf, count); |
2630 | printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res); | 2640 | printk(KERN_DEBUG "pcm_oss: read %li bytes " |
2641 | "(returned %li bytes)\n", (long)count, (long)res); | ||
2631 | return res; | 2642 | return res; |
2632 | } | 2643 | } |
2633 | #endif | 2644 | #endif |
@@ -2646,7 +2657,8 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size | |||
2646 | substream->f_flags = file->f_flags & O_NONBLOCK; | 2657 | substream->f_flags = file->f_flags & O_NONBLOCK; |
2647 | result = snd_pcm_oss_write1(substream, buf, count); | 2658 | result = snd_pcm_oss_write1(substream, buf, count); |
2648 | #ifdef OSS_DEBUG | 2659 | #ifdef OSS_DEBUG |
2649 | printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result); | 2660 | printk(KERN_DEBUG "pcm_oss: write %li bytes (wrote %li bytes)\n", |
2661 | (long)count, (long)result); | ||
2650 | #endif | 2662 | #endif |
2651 | return result; | 2663 | return result; |
2652 | } | 2664 | } |
@@ -2720,7 +2732,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area) | |||
2720 | int err; | 2732 | int err; |
2721 | 2733 | ||
2722 | #ifdef OSS_DEBUG | 2734 | #ifdef OSS_DEBUG |
2723 | printk("pcm_oss: mmap begin\n"); | 2735 | printk(KERN_DEBUG "pcm_oss: mmap begin\n"); |
2724 | #endif | 2736 | #endif |
2725 | pcm_oss_file = file->private_data; | 2737 | pcm_oss_file = file->private_data; |
2726 | switch ((area->vm_flags & (VM_READ | VM_WRITE))) { | 2738 | switch ((area->vm_flags & (VM_READ | VM_WRITE))) { |
@@ -2770,7 +2782,8 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area) | |||
2770 | runtime->silence_threshold = 0; | 2782 | runtime->silence_threshold = 0; |
2771 | runtime->silence_size = 0; | 2783 | runtime->silence_size = 0; |
2772 | #ifdef OSS_DEBUG | 2784 | #ifdef OSS_DEBUG |
2773 | printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes); | 2785 | printk(KERN_DEBUG "pcm_oss: mmap ok, bytes = 0x%x\n", |
2786 | runtime->oss.mmap_bytes); | ||
2774 | #endif | 2787 | #endif |
2775 | /* In mmap mode we never stop */ | 2788 | /* In mmap mode we never stop */ |
2776 | runtime->stop_threshold = runtime->boundary; | 2789 | runtime->stop_threshold = runtime->boundary; |
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h index ca2f4c39be46..b9afab603711 100644 --- a/sound/core/oss/pcm_plugin.h +++ b/sound/core/oss/pcm_plugin.h | |||
@@ -176,9 +176,9 @@ static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_ | |||
176 | #endif | 176 | #endif |
177 | 177 | ||
178 | #ifdef PLUGIN_DEBUG | 178 | #ifdef PLUGIN_DEBUG |
179 | #define pdprintf( fmt, args... ) printk( "plugin: " fmt, ##args) | 179 | #define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args) |
180 | #else | 180 | #else |
181 | #define pdprintf( fmt, args... ) | 181 | #define pdprintf(fmt, args...) |
182 | #endif | 182 | #endif |
183 | 183 | ||
184 | #endif /* __PCM_PLUGIN_H */ | 184 | #endif /* __PCM_PLUGIN_H */ |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 192a433a2403..145931a9ff30 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -667,7 +667,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) | |||
667 | spin_lock_init(&substream->self_group.lock); | 667 | spin_lock_init(&substream->self_group.lock); |
668 | INIT_LIST_HEAD(&substream->self_group.substreams); | 668 | INIT_LIST_HEAD(&substream->self_group.substreams); |
669 | list_add_tail(&substream->link_list, &substream->self_group.substreams); | 669 | list_add_tail(&substream->link_list, &substream->self_group.substreams); |
670 | spin_lock_init(&substream->timer_lock); | ||
671 | atomic_set(&substream->mmap_count, 0); | 670 | atomic_set(&substream->mmap_count, 0); |
672 | prev = substream; | 671 | prev = substream; |
673 | } | 672 | } |
@@ -692,7 +691,7 @@ EXPORT_SYMBOL(snd_pcm_new_stream); | |||
692 | * | 691 | * |
693 | * Returns zero if successful, or a negative error code on failure. | 692 | * Returns zero if successful, or a negative error code on failure. |
694 | */ | 693 | */ |
695 | int snd_pcm_new(struct snd_card *card, char *id, int device, | 694 | int snd_pcm_new(struct snd_card *card, const char *id, int device, |
696 | int playback_count, int capture_count, | 695 | int playback_count, int capture_count, |
697 | struct snd_pcm ** rpcm) | 696 | struct snd_pcm ** rpcm) |
698 | { | 697 | { |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 921691080f35..fbb2e391591e 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -125,23 +125,32 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
125 | } | 125 | } |
126 | } | 126 | } |
127 | 127 | ||
128 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
129 | #define xrun_debug(substream) ((substream)->pstr->xrun_debug) | ||
130 | #else | ||
131 | #define xrun_debug(substream) 0 | ||
132 | #endif | ||
133 | |||
134 | #define dump_stack_on_xrun(substream) do { \ | ||
135 | if (xrun_debug(substream) > 1) \ | ||
136 | dump_stack(); \ | ||
137 | } while (0) | ||
138 | |||
128 | static void xrun(struct snd_pcm_substream *substream) | 139 | static void xrun(struct snd_pcm_substream *substream) |
129 | { | 140 | { |
130 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | 141 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); |
131 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 142 | if (xrun_debug(substream)) { |
132 | if (substream->pstr->xrun_debug) { | ||
133 | snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", | 143 | snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", |
134 | substream->pcm->card->number, | 144 | substream->pcm->card->number, |
135 | substream->pcm->device, | 145 | substream->pcm->device, |
136 | substream->stream ? 'c' : 'p'); | 146 | substream->stream ? 'c' : 'p'); |
137 | if (substream->pstr->xrun_debug > 1) | 147 | dump_stack_on_xrun(substream); |
138 | dump_stack(); | ||
139 | } | 148 | } |
140 | #endif | ||
141 | } | 149 | } |
142 | 150 | ||
143 | static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, | 151 | static snd_pcm_uframes_t |
144 | struct snd_pcm_runtime *runtime) | 152 | snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, |
153 | struct snd_pcm_runtime *runtime) | ||
145 | { | 154 | { |
146 | snd_pcm_uframes_t pos; | 155 | snd_pcm_uframes_t pos; |
147 | 156 | ||
@@ -150,17 +159,21 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substre | |||
150 | pos = substream->ops->pointer(substream); | 159 | pos = substream->ops->pointer(substream); |
151 | if (pos == SNDRV_PCM_POS_XRUN) | 160 | if (pos == SNDRV_PCM_POS_XRUN) |
152 | return pos; /* XRUN */ | 161 | return pos; /* XRUN */ |
153 | #ifdef CONFIG_SND_DEBUG | ||
154 | if (pos >= runtime->buffer_size) { | 162 | if (pos >= runtime->buffer_size) { |
155 | snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); | 163 | if (printk_ratelimit()) { |
164 | snd_printd(KERN_ERR "BUG: stream = %i, pos = 0x%lx, " | ||
165 | "buffer size = 0x%lx, period size = 0x%lx\n", | ||
166 | substream->stream, pos, runtime->buffer_size, | ||
167 | runtime->period_size); | ||
168 | } | ||
169 | pos = 0; | ||
156 | } | 170 | } |
157 | #endif | ||
158 | pos -= pos % runtime->min_align; | 171 | pos -= pos % runtime->min_align; |
159 | return pos; | 172 | return pos; |
160 | } | 173 | } |
161 | 174 | ||
162 | static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | 175 | static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, |
163 | struct snd_pcm_runtime *runtime) | 176 | struct snd_pcm_runtime *runtime) |
164 | { | 177 | { |
165 | snd_pcm_uframes_t avail; | 178 | snd_pcm_uframes_t avail; |
166 | 179 | ||
@@ -182,11 +195,21 @@ static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream | |||
182 | return 0; | 195 | return 0; |
183 | } | 196 | } |
184 | 197 | ||
185 | static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | 198 | #define hw_ptr_error(substream, fmt, args...) \ |
199 | do { \ | ||
200 | if (xrun_debug(substream)) { \ | ||
201 | if (printk_ratelimit()) { \ | ||
202 | snd_printd("PCM: " fmt, ##args); \ | ||
203 | } \ | ||
204 | dump_stack_on_xrun(substream); \ | ||
205 | } \ | ||
206 | } while (0) | ||
207 | |||
208 | static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | ||
186 | { | 209 | { |
187 | struct snd_pcm_runtime *runtime = substream->runtime; | 210 | struct snd_pcm_runtime *runtime = substream->runtime; |
188 | snd_pcm_uframes_t pos; | 211 | snd_pcm_uframes_t pos; |
189 | snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt; | 212 | snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base; |
190 | snd_pcm_sframes_t delta; | 213 | snd_pcm_sframes_t delta; |
191 | 214 | ||
192 | pos = snd_pcm_update_hw_ptr_pos(substream, runtime); | 215 | pos = snd_pcm_update_hw_ptr_pos(substream, runtime); |
@@ -194,36 +217,53 @@ static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *subs | |||
194 | xrun(substream); | 217 | xrun(substream); |
195 | return -EPIPE; | 218 | return -EPIPE; |
196 | } | 219 | } |
197 | if (runtime->period_size == runtime->buffer_size) | 220 | hw_base = runtime->hw_ptr_base; |
198 | goto __next_buf; | 221 | new_hw_ptr = hw_base + pos; |
199 | new_hw_ptr = runtime->hw_ptr_base + pos; | ||
200 | hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; | 222 | hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; |
201 | 223 | delta = new_hw_ptr - hw_ptr_interrupt; | |
202 | delta = hw_ptr_interrupt - new_hw_ptr; | 224 | if (hw_ptr_interrupt >= runtime->boundary) { |
203 | if (delta > 0) { | 225 | hw_ptr_interrupt -= runtime->boundary; |
204 | if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) { | 226 | if (hw_base < runtime->boundary / 2) |
205 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 227 | /* hw_base was already lapped; recalc delta */ |
206 | if (runtime->periods > 1 && substream->pstr->xrun_debug) { | 228 | delta = new_hw_ptr - hw_ptr_interrupt; |
207 | snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); | 229 | } |
208 | if (substream->pstr->xrun_debug > 1) | 230 | if (delta < 0) { |
209 | dump_stack(); | 231 | delta += runtime->buffer_size; |
210 | } | 232 | if (delta < 0) { |
211 | #endif | 233 | hw_ptr_error(substream, |
212 | return 0; | 234 | "Unexpected hw_pointer value " |
235 | "(stream=%i, pos=%ld, intr_ptr=%ld)\n", | ||
236 | substream->stream, (long)pos, | ||
237 | (long)hw_ptr_interrupt); | ||
238 | /* rebase to interrupt position */ | ||
239 | hw_base = new_hw_ptr = hw_ptr_interrupt; | ||
240 | /* align hw_base to buffer_size */ | ||
241 | hw_base -= hw_base % runtime->buffer_size; | ||
242 | delta = 0; | ||
243 | } else { | ||
244 | hw_base += runtime->buffer_size; | ||
245 | if (hw_base >= runtime->boundary) | ||
246 | hw_base = 0; | ||
247 | new_hw_ptr = hw_base + pos; | ||
213 | } | 248 | } |
214 | __next_buf: | ||
215 | runtime->hw_ptr_base += runtime->buffer_size; | ||
216 | if (runtime->hw_ptr_base == runtime->boundary) | ||
217 | runtime->hw_ptr_base = 0; | ||
218 | new_hw_ptr = runtime->hw_ptr_base + pos; | ||
219 | } | 249 | } |
220 | 250 | if (delta > runtime->period_size) { | |
251 | hw_ptr_error(substream, | ||
252 | "Lost interrupts? " | ||
253 | "(stream=%i, delta=%ld, intr_ptr=%ld)\n", | ||
254 | substream->stream, (long)delta, | ||
255 | (long)hw_ptr_interrupt); | ||
256 | /* rebase hw_ptr_interrupt */ | ||
257 | hw_ptr_interrupt = | ||
258 | new_hw_ptr - new_hw_ptr % runtime->period_size; | ||
259 | } | ||
221 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 260 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
222 | runtime->silence_size > 0) | 261 | runtime->silence_size > 0) |
223 | snd_pcm_playback_silence(substream, new_hw_ptr); | 262 | snd_pcm_playback_silence(substream, new_hw_ptr); |
224 | 263 | ||
264 | runtime->hw_ptr_base = hw_base; | ||
225 | runtime->status->hw_ptr = new_hw_ptr; | 265 | runtime->status->hw_ptr = new_hw_ptr; |
226 | runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size; | 266 | runtime->hw_ptr_interrupt = hw_ptr_interrupt; |
227 | 267 | ||
228 | return snd_pcm_update_hw_ptr_post(substream, runtime); | 268 | return snd_pcm_update_hw_ptr_post(substream, runtime); |
229 | } | 269 | } |
@@ -233,7 +273,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) | |||
233 | { | 273 | { |
234 | struct snd_pcm_runtime *runtime = substream->runtime; | 274 | struct snd_pcm_runtime *runtime = substream->runtime; |
235 | snd_pcm_uframes_t pos; | 275 | snd_pcm_uframes_t pos; |
236 | snd_pcm_uframes_t old_hw_ptr, new_hw_ptr; | 276 | snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; |
237 | snd_pcm_sframes_t delta; | 277 | snd_pcm_sframes_t delta; |
238 | 278 | ||
239 | old_hw_ptr = runtime->status->hw_ptr; | 279 | old_hw_ptr = runtime->status->hw_ptr; |
@@ -242,29 +282,38 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) | |||
242 | xrun(substream); | 282 | xrun(substream); |
243 | return -EPIPE; | 283 | return -EPIPE; |
244 | } | 284 | } |
245 | new_hw_ptr = runtime->hw_ptr_base + pos; | 285 | hw_base = runtime->hw_ptr_base; |
246 | 286 | new_hw_ptr = hw_base + pos; | |
247 | delta = old_hw_ptr - new_hw_ptr; | 287 | |
248 | if (delta > 0) { | 288 | delta = new_hw_ptr - old_hw_ptr; |
249 | if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) { | 289 | if (delta < 0) { |
250 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 290 | delta += runtime->buffer_size; |
251 | if (runtime->periods > 2 && substream->pstr->xrun_debug) { | 291 | if (delta < 0) { |
252 | snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); | 292 | hw_ptr_error(substream, |
253 | if (substream->pstr->xrun_debug > 1) | 293 | "Unexpected hw_pointer value [2] " |
254 | dump_stack(); | 294 | "(stream=%i, pos=%ld, old_ptr=%ld)\n", |
255 | } | 295 | substream->stream, (long)pos, |
256 | #endif | 296 | (long)old_hw_ptr); |
257 | return 0; | 297 | return 0; |
258 | } | 298 | } |
259 | runtime->hw_ptr_base += runtime->buffer_size; | 299 | hw_base += runtime->buffer_size; |
260 | if (runtime->hw_ptr_base == runtime->boundary) | 300 | if (hw_base >= runtime->boundary) |
261 | runtime->hw_ptr_base = 0; | 301 | hw_base = 0; |
262 | new_hw_ptr = runtime->hw_ptr_base + pos; | 302 | new_hw_ptr = hw_base + pos; |
303 | } | ||
304 | if (delta > runtime->period_size && runtime->periods > 1) { | ||
305 | hw_ptr_error(substream, | ||
306 | "hw_ptr skipping! " | ||
307 | "(pos=%ld, delta=%ld, period=%ld)\n", | ||
308 | (long)pos, (long)delta, | ||
309 | (long)runtime->period_size); | ||
310 | return 0; | ||
263 | } | 311 | } |
264 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 312 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
265 | runtime->silence_size > 0) | 313 | runtime->silence_size > 0) |
266 | snd_pcm_playback_silence(substream, new_hw_ptr); | 314 | snd_pcm_playback_silence(substream, new_hw_ptr); |
267 | 315 | ||
316 | runtime->hw_ptr_base = hw_base; | ||
268 | runtime->status->hw_ptr = new_hw_ptr; | 317 | runtime->status->hw_ptr = new_hw_ptr; |
269 | 318 | ||
270 | return snd_pcm_update_hw_ptr_post(substream, runtime); | 319 | return snd_pcm_update_hw_ptr_post(substream, runtime); |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a789efc9df39..d9b8f5379428 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -186,7 +186,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, | |||
186 | if (!(params->rmask & (1 << k))) | 186 | if (!(params->rmask & (1 << k))) |
187 | continue; | 187 | continue; |
188 | #ifdef RULES_DEBUG | 188 | #ifdef RULES_DEBUG |
189 | printk("%s = ", snd_pcm_hw_param_names[k]); | 189 | printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]); |
190 | printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); | 190 | printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); |
191 | #endif | 191 | #endif |
192 | changed = snd_mask_refine(m, constrs_mask(constrs, k)); | 192 | changed = snd_mask_refine(m, constrs_mask(constrs, k)); |
@@ -206,7 +206,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, | |||
206 | if (!(params->rmask & (1 << k))) | 206 | if (!(params->rmask & (1 << k))) |
207 | continue; | 207 | continue; |
208 | #ifdef RULES_DEBUG | 208 | #ifdef RULES_DEBUG |
209 | printk("%s = ", snd_pcm_hw_param_names[k]); | 209 | printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]); |
210 | if (i->empty) | 210 | if (i->empty) |
211 | printk("empty"); | 211 | printk("empty"); |
212 | else | 212 | else |
@@ -251,7 +251,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, | |||
251 | if (!doit) | 251 | if (!doit) |
252 | continue; | 252 | continue; |
253 | #ifdef RULES_DEBUG | 253 | #ifdef RULES_DEBUG |
254 | printk("Rule %d [%p]: ", k, r->func); | 254 | printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func); |
255 | if (r->var >= 0) { | 255 | if (r->var >= 0) { |
256 | printk("%s = ", snd_pcm_hw_param_names[r->var]); | 256 | printk("%s = ", snd_pcm_hw_param_names[r->var]); |
257 | if (hw_is_mask(r->var)) { | 257 | if (hw_is_mask(r->var)) { |
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index 2c89c04f2916..ca8068b63d6c 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c | |||
@@ -85,25 +85,19 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) | |||
85 | 85 | ||
86 | static int snd_pcm_timer_start(struct snd_timer * timer) | 86 | static int snd_pcm_timer_start(struct snd_timer * timer) |
87 | { | 87 | { |
88 | unsigned long flags; | ||
89 | struct snd_pcm_substream *substream; | 88 | struct snd_pcm_substream *substream; |
90 | 89 | ||
91 | substream = snd_timer_chip(timer); | 90 | substream = snd_timer_chip(timer); |
92 | spin_lock_irqsave(&substream->timer_lock, flags); | ||
93 | substream->timer_running = 1; | 91 | substream->timer_running = 1; |
94 | spin_unlock_irqrestore(&substream->timer_lock, flags); | ||
95 | return 0; | 92 | return 0; |
96 | } | 93 | } |
97 | 94 | ||
98 | static int snd_pcm_timer_stop(struct snd_timer * timer) | 95 | static int snd_pcm_timer_stop(struct snd_timer * timer) |
99 | { | 96 | { |
100 | unsigned long flags; | ||
101 | struct snd_pcm_substream *substream; | 97 | struct snd_pcm_substream *substream; |
102 | 98 | ||
103 | substream = snd_timer_chip(timer); | 99 | substream = snd_timer_chip(timer); |
104 | spin_lock_irqsave(&substream->timer_lock, flags); | ||
105 | substream->timer_running = 0; | 100 | substream->timer_running = 0; |
106 | spin_unlock_irqrestore(&substream->timer_lock, flags); | ||
107 | return 0; | 101 | return 0; |
108 | } | 102 | } |
109 | 103 | ||
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 002777ba336a..473247c8e6d3 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -224,156 +224,143 @@ int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) | |||
224 | return 0; | 224 | return 0; |
225 | } | 225 | } |
226 | 226 | ||
227 | int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, | 227 | /* look for an available substream for the given stream direction; |
228 | int mode, struct snd_rawmidi_file * rfile) | 228 | * if a specific subdevice is given, try to assign it |
229 | */ | ||
230 | static int assign_substream(struct snd_rawmidi *rmidi, int subdevice, | ||
231 | int stream, int mode, | ||
232 | struct snd_rawmidi_substream **sub_ret) | ||
233 | { | ||
234 | struct snd_rawmidi_substream *substream; | ||
235 | struct snd_rawmidi_str *s = &rmidi->streams[stream]; | ||
236 | static unsigned int info_flags[2] = { | ||
237 | [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT, | ||
238 | [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT, | ||
239 | }; | ||
240 | |||
241 | if (!(rmidi->info_flags & info_flags[stream])) | ||
242 | return -ENXIO; | ||
243 | if (subdevice >= 0 && subdevice >= s->substream_count) | ||
244 | return -ENODEV; | ||
245 | if (s->substream_opened >= s->substream_count) | ||
246 | return -EAGAIN; | ||
247 | |||
248 | list_for_each_entry(substream, &s->substreams, list) { | ||
249 | if (substream->opened) { | ||
250 | if (stream == SNDRV_RAWMIDI_STREAM_INPUT || | ||
251 | !(mode & SNDRV_RAWMIDI_LFLG_APPEND)) | ||
252 | continue; | ||
253 | } | ||
254 | if (subdevice < 0 || subdevice == substream->number) { | ||
255 | *sub_ret = substream; | ||
256 | return 0; | ||
257 | } | ||
258 | } | ||
259 | return -EAGAIN; | ||
260 | } | ||
261 | |||
262 | /* open and do ref-counting for the given substream */ | ||
263 | static int open_substream(struct snd_rawmidi *rmidi, | ||
264 | struct snd_rawmidi_substream *substream, | ||
265 | int mode) | ||
266 | { | ||
267 | int err; | ||
268 | |||
269 | err = snd_rawmidi_runtime_create(substream); | ||
270 | if (err < 0) | ||
271 | return err; | ||
272 | err = substream->ops->open(substream); | ||
273 | if (err < 0) | ||
274 | return err; | ||
275 | substream->opened = 1; | ||
276 | if (substream->use_count++ == 0) | ||
277 | substream->active_sensing = 1; | ||
278 | if (mode & SNDRV_RAWMIDI_LFLG_APPEND) | ||
279 | substream->append = 1; | ||
280 | rmidi->streams[substream->stream].substream_opened++; | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static void close_substream(struct snd_rawmidi *rmidi, | ||
285 | struct snd_rawmidi_substream *substream, | ||
286 | int cleanup); | ||
287 | |||
288 | static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, | ||
289 | struct snd_rawmidi_file *rfile) | ||
229 | { | 290 | { |
230 | struct snd_rawmidi *rmidi; | ||
231 | struct list_head *list1, *list2; | ||
232 | struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; | 291 | struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; |
233 | struct snd_rawmidi_runtime *input = NULL, *output = NULL; | ||
234 | int err; | 292 | int err; |
235 | 293 | ||
236 | if (rfile) | 294 | rfile->input = rfile->output = NULL; |
237 | rfile->input = rfile->output = NULL; | ||
238 | mutex_lock(®ister_mutex); | ||
239 | rmidi = snd_rawmidi_search(card, device); | ||
240 | mutex_unlock(®ister_mutex); | ||
241 | if (rmidi == NULL) { | ||
242 | err = -ENODEV; | ||
243 | goto __error1; | ||
244 | } | ||
245 | if (!try_module_get(rmidi->card->module)) { | ||
246 | err = -EFAULT; | ||
247 | goto __error1; | ||
248 | } | ||
249 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | ||
250 | mutex_lock(&rmidi->open_mutex); | ||
251 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | 295 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { |
252 | if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) { | 296 | err = assign_substream(rmidi, subdevice, |
253 | err = -ENXIO; | 297 | SNDRV_RAWMIDI_STREAM_INPUT, |
254 | goto __error; | 298 | mode, &sinput); |
255 | } | 299 | if (err < 0) |
256 | if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) { | ||
257 | err = -ENODEV; | ||
258 | goto __error; | ||
259 | } | ||
260 | if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >= | ||
261 | rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) { | ||
262 | err = -EAGAIN; | ||
263 | goto __error; | 300 | goto __error; |
264 | } | ||
265 | } | 301 | } |
266 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | 302 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { |
267 | if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) { | 303 | err = assign_substream(rmidi, subdevice, |
268 | err = -ENXIO; | 304 | SNDRV_RAWMIDI_STREAM_OUTPUT, |
269 | goto __error; | 305 | mode, &soutput); |
270 | } | 306 | if (err < 0) |
271 | if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) { | ||
272 | err = -ENODEV; | ||
273 | goto __error; | ||
274 | } | ||
275 | if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >= | ||
276 | rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) { | ||
277 | err = -EAGAIN; | ||
278 | goto __error; | 307 | goto __error; |
279 | } | ||
280 | } | ||
281 | list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next; | ||
282 | while (1) { | ||
283 | if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { | ||
284 | sinput = NULL; | ||
285 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | ||
286 | err = -EAGAIN; | ||
287 | goto __error; | ||
288 | } | ||
289 | break; | ||
290 | } | ||
291 | sinput = list_entry(list1, struct snd_rawmidi_substream, list); | ||
292 | if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened) | ||
293 | goto __nexti; | ||
294 | if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number)) | ||
295 | break; | ||
296 | __nexti: | ||
297 | list1 = list1->next; | ||
298 | } | 308 | } |
299 | list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next; | 309 | |
300 | while (1) { | 310 | if (sinput) { |
301 | if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { | 311 | err = open_substream(rmidi, sinput, mode); |
302 | soutput = NULL; | 312 | if (err < 0) |
303 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | ||
304 | err = -EAGAIN; | ||
305 | goto __error; | ||
306 | } | ||
307 | break; | ||
308 | } | ||
309 | soutput = list_entry(list2, struct snd_rawmidi_substream, list); | ||
310 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | ||
311 | if (mode & SNDRV_RAWMIDI_LFLG_APPEND) { | ||
312 | if (soutput->opened && !soutput->append) | ||
313 | goto __nexto; | ||
314 | } else { | ||
315 | if (soutput->opened) | ||
316 | goto __nexto; | ||
317 | } | ||
318 | } | ||
319 | if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number)) | ||
320 | break; | ||
321 | __nexto: | ||
322 | list2 = list2->next; | ||
323 | } | ||
324 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | ||
325 | if ((err = snd_rawmidi_runtime_create(sinput)) < 0) | ||
326 | goto __error; | ||
327 | input = sinput->runtime; | ||
328 | if ((err = sinput->ops->open(sinput)) < 0) | ||
329 | goto __error; | 313 | goto __error; |
330 | sinput->opened = 1; | ||
331 | rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++; | ||
332 | } else { | ||
333 | sinput = NULL; | ||
334 | } | 314 | } |
335 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | 315 | if (soutput) { |
336 | if (soutput->opened) | 316 | err = open_substream(rmidi, soutput, mode); |
337 | goto __skip_output; | 317 | if (err < 0) { |
338 | if ((err = snd_rawmidi_runtime_create(soutput)) < 0) { | 318 | if (sinput) |
339 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) | 319 | close_substream(rmidi, sinput, 0); |
340 | sinput->ops->close(sinput); | ||
341 | goto __error; | ||
342 | } | ||
343 | output = soutput->runtime; | ||
344 | if ((err = soutput->ops->open(soutput)) < 0) { | ||
345 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) | ||
346 | sinput->ops->close(sinput); | ||
347 | goto __error; | 320 | goto __error; |
348 | } | 321 | } |
349 | __skip_output: | ||
350 | soutput->opened = 1; | ||
351 | if (mode & SNDRV_RAWMIDI_LFLG_APPEND) | ||
352 | soutput->append = 1; | ||
353 | if (soutput->use_count++ == 0) | ||
354 | soutput->active_sensing = 1; | ||
355 | rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++; | ||
356 | } else { | ||
357 | soutput = NULL; | ||
358 | } | ||
359 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | ||
360 | mutex_unlock(&rmidi->open_mutex); | ||
361 | if (rfile) { | ||
362 | rfile->rmidi = rmidi; | ||
363 | rfile->input = sinput; | ||
364 | rfile->output = soutput; | ||
365 | } | 322 | } |
323 | |||
324 | rfile->rmidi = rmidi; | ||
325 | rfile->input = sinput; | ||
326 | rfile->output = soutput; | ||
366 | return 0; | 327 | return 0; |
367 | 328 | ||
368 | __error: | 329 | __error: |
369 | if (input != NULL) | 330 | if (sinput && sinput->runtime) |
370 | snd_rawmidi_runtime_free(sinput); | 331 | snd_rawmidi_runtime_free(sinput); |
371 | if (output != NULL) | 332 | if (soutput && soutput->runtime) |
372 | snd_rawmidi_runtime_free(soutput); | 333 | snd_rawmidi_runtime_free(soutput); |
373 | module_put(rmidi->card->module); | 334 | return err; |
374 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | 335 | } |
375 | mutex_unlock(&rmidi->open_mutex); | 336 | |
376 | __error1: | 337 | /* called from sound/core/seq/seq_midi.c */ |
338 | int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, | ||
339 | int mode, struct snd_rawmidi_file * rfile) | ||
340 | { | ||
341 | struct snd_rawmidi *rmidi; | ||
342 | int err; | ||
343 | |||
344 | if (snd_BUG_ON(!rfile)) | ||
345 | return -EINVAL; | ||
346 | |||
347 | mutex_lock(®ister_mutex); | ||
348 | rmidi = snd_rawmidi_search(card, device); | ||
349 | if (rmidi == NULL) { | ||
350 | mutex_unlock(®ister_mutex); | ||
351 | return -ENODEV; | ||
352 | } | ||
353 | if (!try_module_get(rmidi->card->module)) { | ||
354 | mutex_unlock(®ister_mutex); | ||
355 | return -ENXIO; | ||
356 | } | ||
357 | mutex_unlock(®ister_mutex); | ||
358 | |||
359 | mutex_lock(&rmidi->open_mutex); | ||
360 | err = rawmidi_open_priv(rmidi, subdevice, mode, rfile); | ||
361 | mutex_unlock(&rmidi->open_mutex); | ||
362 | if (err < 0) | ||
363 | module_put(rmidi->card->module); | ||
377 | return err; | 364 | return err; |
378 | } | 365 | } |
379 | 366 | ||
@@ -385,10 +372,13 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
385 | unsigned short fflags; | 372 | unsigned short fflags; |
386 | int err; | 373 | int err; |
387 | struct snd_rawmidi *rmidi; | 374 | struct snd_rawmidi *rmidi; |
388 | struct snd_rawmidi_file *rawmidi_file; | 375 | struct snd_rawmidi_file *rawmidi_file = NULL; |
389 | wait_queue_t wait; | 376 | wait_queue_t wait; |
390 | struct snd_ctl_file *kctl; | 377 | struct snd_ctl_file *kctl; |
391 | 378 | ||
379 | if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) | ||
380 | return -EINVAL; /* invalid combination */ | ||
381 | |||
392 | if (maj == snd_major) { | 382 | if (maj == snd_major) { |
393 | rmidi = snd_lookup_minor_data(iminor(inode), | 383 | rmidi = snd_lookup_minor_data(iminor(inode), |
394 | SNDRV_DEVICE_TYPE_RAWMIDI); | 384 | SNDRV_DEVICE_TYPE_RAWMIDI); |
@@ -402,24 +392,25 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
402 | 392 | ||
403 | if (rmidi == NULL) | 393 | if (rmidi == NULL) |
404 | return -ENODEV; | 394 | return -ENODEV; |
405 | if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) | 395 | |
406 | return -EINVAL; /* invalid combination */ | 396 | if (!try_module_get(rmidi->card->module)) |
397 | return -ENXIO; | ||
398 | |||
399 | mutex_lock(&rmidi->open_mutex); | ||
407 | card = rmidi->card; | 400 | card = rmidi->card; |
408 | err = snd_card_file_add(card, file); | 401 | err = snd_card_file_add(card, file); |
409 | if (err < 0) | 402 | if (err < 0) |
410 | return -ENODEV; | 403 | goto __error_card; |
411 | fflags = snd_rawmidi_file_flags(file); | 404 | fflags = snd_rawmidi_file_flags(file); |
412 | if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */ | 405 | if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */ |
413 | fflags |= SNDRV_RAWMIDI_LFLG_APPEND; | 406 | fflags |= SNDRV_RAWMIDI_LFLG_APPEND; |
414 | fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK; | ||
415 | rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); | 407 | rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); |
416 | if (rawmidi_file == NULL) { | 408 | if (rawmidi_file == NULL) { |
417 | snd_card_file_remove(card, file); | 409 | err = -ENOMEM; |
418 | return -ENOMEM; | 410 | goto __error; |
419 | } | 411 | } |
420 | init_waitqueue_entry(&wait, current); | 412 | init_waitqueue_entry(&wait, current); |
421 | add_wait_queue(&rmidi->open_wait, &wait); | 413 | add_wait_queue(&rmidi->open_wait, &wait); |
422 | mutex_lock(&rmidi->open_mutex); | ||
423 | while (1) { | 414 | while (1) { |
424 | subdevice = -1; | 415 | subdevice = -1; |
425 | read_lock(&card->ctl_files_rwlock); | 416 | read_lock(&card->ctl_files_rwlock); |
@@ -431,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
431 | } | 422 | } |
432 | } | 423 | } |
433 | read_unlock(&card->ctl_files_rwlock); | 424 | read_unlock(&card->ctl_files_rwlock); |
434 | err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device, | 425 | err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file); |
435 | subdevice, fflags, rawmidi_file); | ||
436 | if (err >= 0) | 426 | if (err >= 0) |
437 | break; | 427 | break; |
438 | if (err == -EAGAIN) { | 428 | if (err == -EAGAIN) { |
@@ -451,67 +441,89 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
451 | break; | 441 | break; |
452 | } | 442 | } |
453 | } | 443 | } |
444 | remove_wait_queue(&rmidi->open_wait, &wait); | ||
445 | if (err < 0) { | ||
446 | kfree(rawmidi_file); | ||
447 | goto __error; | ||
448 | } | ||
454 | #ifdef CONFIG_SND_OSSEMUL | 449 | #ifdef CONFIG_SND_OSSEMUL |
455 | if (rawmidi_file->input && rawmidi_file->input->runtime) | 450 | if (rawmidi_file->input && rawmidi_file->input->runtime) |
456 | rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR); | 451 | rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR); |
457 | if (rawmidi_file->output && rawmidi_file->output->runtime) | 452 | if (rawmidi_file->output && rawmidi_file->output->runtime) |
458 | rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR); | 453 | rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR); |
459 | #endif | 454 | #endif |
460 | remove_wait_queue(&rmidi->open_wait, &wait); | 455 | file->private_data = rawmidi_file; |
461 | if (err >= 0) { | 456 | mutex_unlock(&rmidi->open_mutex); |
462 | file->private_data = rawmidi_file; | 457 | return 0; |
463 | } else { | 458 | |
464 | snd_card_file_remove(card, file); | 459 | __error: |
465 | kfree(rawmidi_file); | 460 | snd_card_file_remove(card, file); |
466 | } | 461 | __error_card: |
467 | mutex_unlock(&rmidi->open_mutex); | 462 | mutex_unlock(&rmidi->open_mutex); |
463 | module_put(rmidi->card->module); | ||
468 | return err; | 464 | return err; |
469 | } | 465 | } |
470 | 466 | ||
471 | int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile) | 467 | static void close_substream(struct snd_rawmidi *rmidi, |
468 | struct snd_rawmidi_substream *substream, | ||
469 | int cleanup) | ||
472 | { | 470 | { |
473 | struct snd_rawmidi *rmidi; | 471 | rmidi->streams[substream->stream].substream_opened--; |
474 | struct snd_rawmidi_substream *substream; | 472 | if (--substream->use_count) |
475 | struct snd_rawmidi_runtime *runtime; | 473 | return; |
476 | 474 | ||
477 | if (snd_BUG_ON(!rfile)) | 475 | if (cleanup) { |
478 | return -ENXIO; | 476 | if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) |
479 | rmidi = rfile->rmidi; | 477 | snd_rawmidi_input_trigger(substream, 0); |
480 | mutex_lock(&rmidi->open_mutex); | 478 | else { |
481 | if (rfile->input != NULL) { | ||
482 | substream = rfile->input; | ||
483 | rfile->input = NULL; | ||
484 | runtime = substream->runtime; | ||
485 | snd_rawmidi_input_trigger(substream, 0); | ||
486 | substream->ops->close(substream); | ||
487 | if (runtime->private_free != NULL) | ||
488 | runtime->private_free(substream); | ||
489 | snd_rawmidi_runtime_free(substream); | ||
490 | substream->opened = 0; | ||
491 | rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--; | ||
492 | } | ||
493 | if (rfile->output != NULL) { | ||
494 | substream = rfile->output; | ||
495 | rfile->output = NULL; | ||
496 | if (--substream->use_count == 0) { | ||
497 | runtime = substream->runtime; | ||
498 | if (substream->active_sensing) { | 479 | if (substream->active_sensing) { |
499 | unsigned char buf = 0xfe; | 480 | unsigned char buf = 0xfe; |
500 | /* sending single active sensing message to shut the device up */ | 481 | /* sending single active sensing message |
482 | * to shut the device up | ||
483 | */ | ||
501 | snd_rawmidi_kernel_write(substream, &buf, 1); | 484 | snd_rawmidi_kernel_write(substream, &buf, 1); |
502 | } | 485 | } |
503 | if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) | 486 | if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) |
504 | snd_rawmidi_output_trigger(substream, 0); | 487 | snd_rawmidi_output_trigger(substream, 0); |
505 | substream->ops->close(substream); | ||
506 | if (runtime->private_free != NULL) | ||
507 | runtime->private_free(substream); | ||
508 | snd_rawmidi_runtime_free(substream); | ||
509 | substream->opened = 0; | ||
510 | substream->append = 0; | ||
511 | } | 488 | } |
512 | rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--; | ||
513 | } | 489 | } |
490 | substream->ops->close(substream); | ||
491 | if (substream->runtime->private_free) | ||
492 | substream->runtime->private_free(substream); | ||
493 | snd_rawmidi_runtime_free(substream); | ||
494 | substream->opened = 0; | ||
495 | substream->append = 0; | ||
496 | } | ||
497 | |||
498 | static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) | ||
499 | { | ||
500 | struct snd_rawmidi *rmidi; | ||
501 | |||
502 | rmidi = rfile->rmidi; | ||
503 | mutex_lock(&rmidi->open_mutex); | ||
504 | if (rfile->input) { | ||
505 | close_substream(rmidi, rfile->input, 1); | ||
506 | rfile->input = NULL; | ||
507 | } | ||
508 | if (rfile->output) { | ||
509 | close_substream(rmidi, rfile->output, 1); | ||
510 | rfile->output = NULL; | ||
511 | } | ||
512 | rfile->rmidi = NULL; | ||
514 | mutex_unlock(&rmidi->open_mutex); | 513 | mutex_unlock(&rmidi->open_mutex); |
514 | wake_up(&rmidi->open_wait); | ||
515 | } | ||
516 | |||
517 | /* called from sound/core/seq/seq_midi.c */ | ||
518 | int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile) | ||
519 | { | ||
520 | struct snd_rawmidi *rmidi; | ||
521 | |||
522 | if (snd_BUG_ON(!rfile)) | ||
523 | return -ENXIO; | ||
524 | |||
525 | rmidi = rfile->rmidi; | ||
526 | rawmidi_release_priv(rfile); | ||
515 | module_put(rmidi->card->module); | 527 | module_put(rmidi->card->module); |
516 | return 0; | 528 | return 0; |
517 | } | 529 | } |
@@ -520,15 +532,14 @@ static int snd_rawmidi_release(struct inode *inode, struct file *file) | |||
520 | { | 532 | { |
521 | struct snd_rawmidi_file *rfile; | 533 | struct snd_rawmidi_file *rfile; |
522 | struct snd_rawmidi *rmidi; | 534 | struct snd_rawmidi *rmidi; |
523 | int err; | ||
524 | 535 | ||
525 | rfile = file->private_data; | 536 | rfile = file->private_data; |
526 | err = snd_rawmidi_kernel_release(rfile); | ||
527 | rmidi = rfile->rmidi; | 537 | rmidi = rfile->rmidi; |
528 | wake_up(&rmidi->open_wait); | 538 | rawmidi_release_priv(rfile); |
529 | kfree(rfile); | 539 | kfree(rfile); |
530 | snd_card_file_remove(rmidi->card, file); | 540 | snd_card_file_remove(rmidi->card, file); |
531 | return err; | 541 | module_put(rmidi->card->module); |
542 | return 0; | ||
532 | } | 543 | } |
533 | 544 | ||
534 | static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, | 545 | static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, |
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index bf8d2b4cb15e..c0154a959d55 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h | |||
@@ -181,7 +181,7 @@ char *enabled_str(int bool); | |||
181 | /* for debug */ | 181 | /* for debug */ |
182 | #ifdef SNDRV_SEQ_OSS_DEBUG | 182 | #ifdef SNDRV_SEQ_OSS_DEBUG |
183 | extern int seq_oss_debug; | 183 | extern int seq_oss_debug; |
184 | #define debug_printk(x) do { if (seq_oss_debug > 0) snd_printk x; } while (0) | 184 | #define debug_printk(x) do { if (seq_oss_debug > 0) snd_printd x; } while (0) |
185 | #else | 185 | #else |
186 | #define debug_printk(x) /**/ | 186 | #define debug_printk(x) /**/ |
187 | #endif | 187 | #endif |
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index 0101a8b99b73..29896ab23403 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c | |||
@@ -321,7 +321,8 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp) | |||
321 | freeprev = cell; | 321 | freeprev = cell; |
322 | } else { | 322 | } else { |
323 | #if 0 | 323 | #if 0 |
324 | printk("type = %i, source = %i, dest = %i, client = %i\n", | 324 | printk(KERN_DEBUG "type = %i, source = %i, dest = %i, " |
325 | "client = %i\n", | ||
325 | cell->event.type, | 326 | cell->event.type, |
326 | cell->event.source.client, | 327 | cell->event.source.client, |
327 | cell->event.dest.client, | 328 | cell->event.dest.client, |
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 4cc57f902e2c..257624bd1997 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c | |||
@@ -50,18 +50,38 @@ struct link_slave { | |||
50 | struct link_master *master; | 50 | struct link_master *master; |
51 | struct link_ctl_info info; | 51 | struct link_ctl_info info; |
52 | int vals[2]; /* current values */ | 52 | int vals[2]; /* current values */ |
53 | unsigned int flags; | ||
53 | struct snd_kcontrol slave; /* the copy of original control entry */ | 54 | struct snd_kcontrol slave; /* the copy of original control entry */ |
54 | }; | 55 | }; |
55 | 56 | ||
57 | static int slave_update(struct link_slave *slave) | ||
58 | { | ||
59 | struct snd_ctl_elem_value *uctl; | ||
60 | int err, ch; | ||
61 | |||
62 | uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); | ||
63 | if (!uctl) | ||
64 | return -ENOMEM; | ||
65 | uctl->id = slave->slave.id; | ||
66 | err = slave->slave.get(&slave->slave, uctl); | ||
67 | for (ch = 0; ch < slave->info.count; ch++) | ||
68 | slave->vals[ch] = uctl->value.integer.value[ch]; | ||
69 | kfree(uctl); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
56 | /* get the slave ctl info and save the initial values */ | 73 | /* get the slave ctl info and save the initial values */ |
57 | static int slave_init(struct link_slave *slave) | 74 | static int slave_init(struct link_slave *slave) |
58 | { | 75 | { |
59 | struct snd_ctl_elem_info *uinfo; | 76 | struct snd_ctl_elem_info *uinfo; |
60 | struct snd_ctl_elem_value *uctl; | 77 | int err; |
61 | int err, ch; | ||
62 | 78 | ||
63 | if (slave->info.count) | 79 | if (slave->info.count) { |
64 | return 0; /* already initialized */ | 80 | /* already initialized */ |
81 | if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE) | ||
82 | return slave_update(slave); | ||
83 | return 0; | ||
84 | } | ||
65 | 85 | ||
66 | uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); | 86 | uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); |
67 | if (!uinfo) | 87 | if (!uinfo) |
@@ -85,15 +105,7 @@ static int slave_init(struct link_slave *slave) | |||
85 | slave->info.max_val = uinfo->value.integer.max; | 105 | slave->info.max_val = uinfo->value.integer.max; |
86 | kfree(uinfo); | 106 | kfree(uinfo); |
87 | 107 | ||
88 | uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); | 108 | return slave_update(slave); |
89 | if (!uctl) | ||
90 | return -ENOMEM; | ||
91 | uctl->id = slave->slave.id; | ||
92 | err = slave->slave.get(&slave->slave, uctl); | ||
93 | for (ch = 0; ch < slave->info.count; ch++) | ||
94 | slave->vals[ch] = uctl->value.integer.value[ch]; | ||
95 | kfree(uctl); | ||
96 | return 0; | ||
97 | } | 109 | } |
98 | 110 | ||
99 | /* initialize master volume */ | 111 | /* initialize master volume */ |
@@ -229,7 +241,8 @@ static void slave_free(struct snd_kcontrol *kcontrol) | |||
229 | * - logarithmic volume control (dB level), no linear volume | 241 | * - logarithmic volume control (dB level), no linear volume |
230 | * - master can only attenuate the volume, no gain | 242 | * - master can only attenuate the volume, no gain |
231 | */ | 243 | */ |
232 | int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) | 244 | int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave, |
245 | unsigned int flags) | ||
233 | { | 246 | { |
234 | struct link_master *master_link = snd_kcontrol_chip(master); | 247 | struct link_master *master_link = snd_kcontrol_chip(master); |
235 | struct link_slave *srec; | 248 | struct link_slave *srec; |
@@ -241,6 +254,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) | |||
241 | srec->slave = *slave; | 254 | srec->slave = *slave; |
242 | memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd)); | 255 | memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd)); |
243 | srec->master = master_link; | 256 | srec->master = master_link; |
257 | srec->flags = flags; | ||
244 | 258 | ||
245 | /* override callbacks */ | 259 | /* override callbacks */ |
246 | slave->info = slave_info; | 260 | slave->info = slave_info; |
@@ -254,8 +268,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) | |||
254 | list_add_tail(&srec->list, &master_link->slaves); | 268 | list_add_tail(&srec->list, &master_link->slaves); |
255 | return 0; | 269 | return 0; |
256 | } | 270 | } |
257 | 271 | EXPORT_SYMBOL(_snd_ctl_add_slave); | |
258 | EXPORT_SYMBOL(snd_ctl_add_slave); | ||
259 | 272 | ||
260 | /* | 273 | /* |
261 | * ctl callbacks for master controls | 274 | * ctl callbacks for master controls |
@@ -327,8 +340,20 @@ static void master_free(struct snd_kcontrol *kcontrol) | |||
327 | } | 340 | } |
328 | 341 | ||
329 | 342 | ||
330 | /* | 343 | /** |
331 | * Create a virtual master control with the given name | 344 | * snd_ctl_make_virtual_master - Create a virtual master control |
345 | * @name: name string of the control element to create | ||
346 | * @tlv: optional TLV int array for dB information | ||
347 | * | ||
348 | * Creates a virtual matster control with the given name string. | ||
349 | * Returns the created control element, or NULL for errors (ENOMEM). | ||
350 | * | ||
351 | * After creating a vmaster element, you can add the slave controls | ||
352 | * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached(). | ||
353 | * | ||
354 | * The optional argument @tlv can be used to specify the TLV information | ||
355 | * for dB scale of the master control. It should be a single element | ||
356 | * with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB. | ||
332 | */ | 357 | */ |
333 | struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, | 358 | struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, |
334 | const unsigned int *tlv) | 359 | const unsigned int *tlv) |
@@ -367,5 +392,4 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, | |||
367 | 392 | ||
368 | return kctl; | 393 | return kctl; |
369 | } | 394 | } |
370 | |||
371 | EXPORT_SYMBOL(snd_ctl_make_virtual_master); | 395 | EXPORT_SYMBOL(snd_ctl_make_virtual_master); |