aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-03-27 09:44:52 -0500
committerJaroslav Kysela <perex@suse.cz>2006-03-31 10:58:59 -0500
commit060d77b9c04acd7aef60790398a53f731db8c8fe (patch)
treec774bb62e0b8ee4b210c5ad4c2d706a346a23efc
parent3bf75f9b90c981f18f27a0d35a44f488ab68c8ea (diff)
[ALSA] Fix / clean up PCM-OSS setup hooks
- Fix possible race of referring the setup hook from the running PCM - Fix memory leak in an error path of proc write - Clean up the setup hook parser Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--include/sound/pcm_oss.h2
-rw-r--r--sound/core/oss/pcm_oss.c133
2 files changed, 64 insertions, 71 deletions
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
index 1d522aaa66df..39df2baca18a 100644
--- a/include/sound/pcm_oss.h
+++ b/include/sound/pcm_oss.h
@@ -69,7 +69,7 @@ struct snd_pcm_oss_file {
69 69
70struct snd_pcm_oss_substream { 70struct snd_pcm_oss_substream {
71 unsigned oss: 1; /* oss mode */ 71 unsigned oss: 1; /* oss mode */
72 struct snd_pcm_oss_setup *setup; /* active setup */ 72 struct snd_pcm_oss_setup setup; /* active setup */
73}; 73};
74 74
75struct snd_pcm_oss_stream { 75struct snd_pcm_oss_stream {
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index c056cbfe5519..91114c7aeff5 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -208,9 +208,8 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
208 oss_buffer_size = runtime->oss.mmap_bytes; 208 oss_buffer_size = runtime->oss.mmap_bytes;
209 } 209 }
210 210
211 if (substream->oss.setup && 211 if (substream->oss.setup.period_size > 16)
212 substream->oss.setup->period_size > 16) 212 oss_period_size = substream->oss.setup.period_size;
213 oss_period_size = substream->oss.setup->period_size;
214 else if (runtime->oss.fragshift) { 213 else if (runtime->oss.fragshift) {
215 oss_period_size = 1 << runtime->oss.fragshift; 214 oss_period_size = 1 << runtime->oss.fragshift;
216 if (oss_period_size > oss_buffer_size / 2) 215 if (oss_period_size > oss_buffer_size / 2)
@@ -252,10 +251,8 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
252 251
253 oss_periods = oss_buffer_size / oss_period_size; 252 oss_periods = oss_buffer_size / oss_period_size;
254 253
255 if (substream->oss.setup) { 254 if (substream->oss.setup.periods > 1)
256 if (substream->oss.setup->periods > 1) 255 oss_periods = substream->oss.setup.periods;
257 oss_periods = substream->oss.setup->periods;
258 }
259 256
260 s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL); 257 s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
261 if (runtime->oss.maxfrags && s > runtime->oss.maxfrags) 258 if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
@@ -341,12 +338,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
341 goto failure; 338 goto failure;
342 } 339 }
343 340
344 if (atomic_read(&runtime->mmap_count)) { 341 if (atomic_read(&runtime->mmap_count))
345 direct = 1; 342 direct = 1;
346 } else { 343 else
347 struct snd_pcm_oss_setup *setup = substream->oss.setup; 344 direct = substream->oss.setup.direct;
348 direct = (setup != NULL && setup->direct);
349 }
350 345
351 _snd_pcm_hw_params_any(sparams); 346 _snd_pcm_hw_params_any(sparams);
352 _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS); 347 _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
@@ -482,7 +477,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
482 1 : runtime->period_size; 477 1 : runtime->period_size;
483 sw_params->xfer_align = 1; 478 sw_params->xfer_align = 1;
484 if (atomic_read(&runtime->mmap_count) || 479 if (atomic_read(&runtime->mmap_count) ||
485 (substream->oss.setup && substream->oss.setup->nosilence)) { 480 substream->oss.setup.nosilence) {
486 sw_params->silence_threshold = 0; 481 sw_params->silence_threshold = 0;
487 sw_params->silence_size = 0; 482 sw_params->silence_size = 0;
488 } else { 483 } else {
@@ -843,7 +838,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
843 buf += tmp; 838 buf += tmp;
844 bytes -= tmp; 839 bytes -= tmp;
845 xfer += tmp; 840 xfer += tmp;
846 if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) || 841 if (substream->oss.setup.partialfrag ||
847 runtime->oss.buffer_used == runtime->oss.period_bytes) { 842 runtime->oss.buffer_used == runtime->oss.period_bytes) {
848 tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr, 843 tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr,
849 runtime->oss.buffer_used - runtime->oss.period_ptr, 1); 844 runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
@@ -1214,12 +1209,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
1214 1209
1215 if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) 1210 if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1216 return err; 1211 return err;
1217 if (atomic_read(&substream->runtime->mmap_count)) { 1212 if (atomic_read(&substream->runtime->mmap_count))
1218 direct = 1; 1213 direct = 1;
1219 } else { 1214 else
1220 struct snd_pcm_oss_setup *setup = substream->oss.setup; 1215 direct = substream->oss.setup.direct;
1221 direct = (setup != NULL && setup->direct);
1222 }
1223 if (!direct) 1216 if (!direct)
1224 return AFMT_MU_LAW | AFMT_U8 | 1217 return AFMT_MU_LAW | AFMT_U8 |
1225 AFMT_S16_LE | AFMT_S16_BE | 1218 AFMT_S16_LE | AFMT_S16_BE |
@@ -1555,8 +1548,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
1555 } else { 1548 } else {
1556 delay = snd_pcm_oss_bytes(substream, delay); 1549 delay = snd_pcm_oss_bytes(substream, delay);
1557 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 1550 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1558 struct snd_pcm_oss_setup *setup = substream->oss.setup; 1551 if (substream->oss.setup.buggyptr)
1559 if (setup && setup->buggyptr)
1560 info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes; 1552 info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes;
1561 else 1553 else
1562 info.blocks = (delay + fixup) / runtime->oss.period_bytes; 1554 info.blocks = (delay + fixup) / runtime->oss.period_bytes;
@@ -1638,37 +1630,34 @@ static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int str
1638 return -EINVAL; 1630 return -EINVAL;
1639} 1631}
1640 1632
1641static struct snd_pcm_oss_setup *snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream, const char *task_name) 1633static const char *strip_task_path(const char *path)
1642{ 1634{
1643 const char *ptr, *ptrl; 1635 const char *ptr, *ptrl = NULL;
1644 struct snd_pcm_oss_setup *setup; 1636 for (ptr = path; *ptr; ptr++) {
1645
1646 mutex_lock(&pcm->streams[stream].oss.setup_mutex);
1647 for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
1648 if (!strcmp(setup->task_name, task_name)) {
1649 mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
1650 return setup;
1651 }
1652 }
1653 ptr = ptrl = task_name;
1654 while (*ptr) {
1655 if (*ptr == '/') 1637 if (*ptr == '/')
1656 ptrl = ptr + 1; 1638 ptrl = ptr + 1;
1657 ptr++;
1658 }
1659 if (ptrl == task_name) {
1660 goto __not_found;
1661 return NULL;
1662 } 1639 }
1663 for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) { 1640 return ptrl;
1664 if (!strcmp(setup->task_name, ptrl)) { 1641}
1665 mutex_unlock(&pcm->streams[stream].oss.setup_mutex); 1642
1666 return setup; 1643static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
1644 const char *task_name,
1645 struct snd_pcm_oss_setup *rsetup)
1646{
1647 struct snd_pcm_oss_setup *setup;
1648
1649 mutex_lock(&pcm->streams[stream].oss.setup_mutex);
1650 do {
1651 for (setup = pcm->streams[stream].oss.setup_list; setup;
1652 setup = setup->next) {
1653 if (!strcmp(setup->task_name, task_name))
1654 goto out;
1667 } 1655 }
1668 } 1656 } while ((task_name = strip_task_path(task_name)) != NULL);
1669 __not_found: 1657 out:
1658 if (setup)
1659 *rsetup = *setup;
1670 mutex_unlock(&pcm->streams[stream].oss.setup_mutex); 1660 mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
1671 return NULL;
1672} 1661}
1673 1662
1674static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream) 1663static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
@@ -1690,7 +1679,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
1690 struct snd_pcm_runtime *runtime; 1679 struct snd_pcm_runtime *runtime;
1691 1680
1692 substream->oss.oss = 1; 1681 substream->oss.oss = 1;
1693 substream->oss.setup = setup; 1682 substream->oss.setup = *setup;
1694 if (setup->nonblock) 1683 if (setup->nonblock)
1695 substream->ffile->f_flags |= O_NONBLOCK; 1684 substream->ffile->f_flags |= O_NONBLOCK;
1696 else 1685 else
@@ -1733,7 +1722,7 @@ static int snd_pcm_oss_open_file(struct file *file,
1733 struct snd_pcm *pcm, 1722 struct snd_pcm *pcm,
1734 struct snd_pcm_oss_file **rpcm_oss_file, 1723 struct snd_pcm_oss_file **rpcm_oss_file,
1735 int minor, 1724 int minor,
1736 struct snd_pcm_oss_setup **setup) 1725 struct snd_pcm_oss_setup *setup)
1737{ 1726{
1738 int idx, err; 1727 int idx, err;
1739 struct snd_pcm_oss_file *pcm_oss_file; 1728 struct snd_pcm_oss_file *pcm_oss_file;
@@ -1752,7 +1741,7 @@ static int snd_pcm_oss_open_file(struct file *file,
1752 f_mode = FMODE_WRITE; 1741 f_mode = FMODE_WRITE;
1753 1742
1754 for (idx = 0; idx < 2; idx++) { 1743 for (idx = 0; idx < 2; idx++) {
1755 if (! setup[idx] || setup[idx]->disable) 1744 if (setup[idx].disable)
1756 continue; 1745 continue;
1757 if (idx == SNDRV_PCM_STREAM_PLAYBACK) { 1746 if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
1758 if (! (f_mode & FMODE_WRITE)) 1747 if (! (f_mode & FMODE_WRITE))
@@ -1768,7 +1757,7 @@ static int snd_pcm_oss_open_file(struct file *file,
1768 } 1757 }
1769 1758
1770 pcm_oss_file->streams[idx] = substream; 1759 pcm_oss_file->streams[idx] = substream;
1771 snd_pcm_oss_init_substream(substream, setup[idx], minor); 1760 snd_pcm_oss_init_substream(substream, &setup[idx], minor);
1772 } 1761 }
1773 1762
1774 if (! pcm_oss_file->streams[0] && pcm_oss_file->streams[1]) { 1763 if (! pcm_oss_file->streams[0] && pcm_oss_file->streams[1]) {
@@ -1799,7 +1788,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
1799 char task_name[32]; 1788 char task_name[32];
1800 struct snd_pcm *pcm; 1789 struct snd_pcm *pcm;
1801 struct snd_pcm_oss_file *pcm_oss_file; 1790 struct snd_pcm_oss_file *pcm_oss_file;
1802 struct snd_pcm_oss_setup *setup[2]; 1791 struct snd_pcm_oss_setup setup[2];
1803 int nonblock; 1792 int nonblock;
1804 wait_queue_t wait; 1793 wait_queue_t wait;
1805 1794
@@ -1822,9 +1811,11 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
1822 } 1811 }
1823 memset(setup, 0, sizeof(*setup)); 1812 memset(setup, 0, sizeof(*setup));
1824 if (file->f_mode & FMODE_WRITE) 1813 if (file->f_mode & FMODE_WRITE)
1825 setup[0] = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name); 1814 snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1815 task_name, &setup[0]);
1826 if (file->f_mode & FMODE_READ) 1816 if (file->f_mode & FMODE_READ)
1827 setup[1] = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, task_name); 1817 snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE,
1818 task_name, &setup[1]);
1828 1819
1829 nonblock = !!(file->f_flags & O_NONBLOCK); 1820 nonblock = !!(file->f_flags & O_NONBLOCK);
1830 if (!nonblock) 1821 if (!nonblock)
@@ -2249,13 +2240,8 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
2249 2240
2250static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr) 2241static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
2251{ 2242{
2252 unsigned int idx;
2253 struct snd_pcm_substream *substream;
2254 struct snd_pcm_oss_setup *setup, *setupn; 2243 struct snd_pcm_oss_setup *setup, *setupn;
2255 2244
2256 for (idx = 0, substream = pstr->substream;
2257 idx < pstr->substream_count; idx++, substream = substream->next)
2258 substream->oss.setup = NULL;
2259 for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL; 2245 for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL;
2260 setup; setup = setupn) { 2246 setup; setup = setupn) {
2261 setupn = setup->next; 2247 setupn = setup->next;
@@ -2316,21 +2302,28 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
2316 } 2302 }
2317 } while (*str); 2303 } while (*str);
2318 if (setup == NULL) { 2304 if (setup == NULL) {
2319 setup = kmalloc(sizeof(struct snd_pcm_oss_setup), GFP_KERNEL); 2305 setup = kmalloc(sizeof(*setup), GFP_KERNEL);
2320 if (setup) { 2306 if (! setup) {
2321 if (pstr->oss.setup_list == NULL) { 2307 buffer->error = -ENOMEM;
2322 pstr->oss.setup_list = setup; 2308 mutex_lock(&pstr->oss.setup_mutex);
2323 } else { 2309 return;
2324 for (setup1 = pstr->oss.setup_list; setup1->next; setup1 = setup1->next); 2310 }
2325 setup1->next = setup; 2311 if (pstr->oss.setup_list == NULL)
2326 } 2312 pstr->oss.setup_list = setup;
2327 template.task_name = kstrdup(task_name, GFP_KERNEL); 2313 else {
2328 } else { 2314 for (setup1 = pstr->oss.setup_list;
2315 setup1->next; setup1 = setup1->next);
2316 setup1->next = setup;
2317 }
2318 template.task_name = kstrdup(task_name, GFP_KERNEL);
2319 if (! template.task_name) {
2320 kfree(setup);
2329 buffer->error = -ENOMEM; 2321 buffer->error = -ENOMEM;
2322 mutex_lock(&pstr->oss.setup_mutex);
2323 return;
2330 } 2324 }
2331 } 2325 }
2332 if (setup) 2326 *setup = template;
2333 *setup = template;
2334 mutex_unlock(&pstr->oss.setup_mutex); 2327 mutex_unlock(&pstr->oss.setup_mutex);
2335 } 2328 }
2336} 2329}