Commit eb7e7cd8 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Linus Torvalds

[PATCH] ALSA update [6/10] - 2002/07/20

  - added vfree_nocheck()
  - PCM midlevel & EMU10K1 - added support for SG buffer
  - CS4236 - added new ISA PnP ID
  - HDSP - fixed rate rules (OSS emulation works)
parent 81ff6ee4
...@@ -243,8 +243,10 @@ void snd_hidden_vfree(void *obj); ...@@ -243,8 +243,10 @@ void snd_hidden_vfree(void *obj);
#define kfree_nocheck(obj) snd_wrapper_kfree(obj) #define kfree_nocheck(obj) snd_wrapper_kfree(obj)
#define vmalloc(size) snd_hidden_vmalloc(size) #define vmalloc(size) snd_hidden_vmalloc(size)
#define vfree(obj) snd_hidden_vfree(obj) #define vfree(obj) snd_hidden_vfree(obj)
#define vfree_nocheck(obj) snd_wrapper_vfree(obj)
#else #else
#define kfree_nocheck(obj) kfree(obj) #define kfree_nocheck(obj) kfree(obj)
#define vfree_nocheck(obj) vfree(obj)
#endif #endif
void *snd_kcalloc(size_t size, int flags); void *snd_kcalloc(size_t size, int flags);
char *snd_kmalloc_strdup(const char *string, int flags); char *snd_kmalloc_strdup(const char *string, int flags);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include "pcm.h" #include "pcm.h"
#include "pcm_sgbuf.h"
#include "rawmidi.h" #include "rawmidi.h"
#include "hwdep.h" #include "hwdep.h"
#include "ac97_codec.h" #include "ac97_codec.h"
...@@ -1043,7 +1044,7 @@ unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate); ...@@ -1043,7 +1044,7 @@ unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate);
unsigned char snd_emu10k1_sum_vol_attn(unsigned int value); unsigned char snd_emu10k1_sum_vol_attn(unsigned int value);
/* memory allocation */ /* memory allocation */
snd_util_memblk_t *snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size); snd_util_memblk_t *snd_emu10k1_alloc_pages(emu10k1_t *emu, struct snd_sg_buf *sgbuf);
int snd_emu10k1_free_pages(emu10k1_t *emu, snd_util_memblk_t *blk); int snd_emu10k1_free_pages(emu10k1_t *emu, snd_util_memblk_t *blk);
snd_util_memblk_t *snd_emu10k1_synth_alloc(emu10k1_t *emu, unsigned int size); snd_util_memblk_t *snd_emu10k1_synth_alloc(emu10k1_t *emu, unsigned int size);
int snd_emu10k1_synth_free(emu10k1_t *emu, snd_util_memblk_t *blk); int snd_emu10k1_synth_free(emu10k1_t *emu, snd_util_memblk_t *blk);
......
...@@ -96,6 +96,7 @@ typedef struct _snd_pcm_ops { ...@@ -96,6 +96,7 @@ typedef struct _snd_pcm_ops {
void *buf, snd_pcm_uframes_t count); void *buf, snd_pcm_uframes_t count);
int (*silence)(snd_pcm_substream_t *substream, int channel, int (*silence)(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count); snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
void *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
} snd_pcm_ops_t; } snd_pcm_ops_t;
/* /*
...@@ -771,6 +772,9 @@ int snd_pcm_hw_constraint_step(snd_pcm_runtime_t *runtime, ...@@ -771,6 +772,9 @@ int snd_pcm_hw_constraint_step(snd_pcm_runtime_t *runtime,
unsigned int cond, unsigned int cond,
snd_pcm_hw_param_t var, snd_pcm_hw_param_t var,
unsigned long step); unsigned long step);
int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
unsigned int cond,
snd_pcm_hw_param_t var);
int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime, int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime,
unsigned int cond, unsigned int cond,
int var, int var,
......
#ifndef __SOUND_PCM_SGBUF_H
#define __SOUND_PCM_SGBUF_H
/*
* Scatter-Gather PCM access
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
struct snd_sg_page {
void *buf;
dma_addr_t addr;
};
struct snd_sg_buf {
int size; /* allocated byte size (= runtime->dma_bytes) */
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table;
struct pci_dev *pci;
};
typedef struct snd_sg_buf snd_pcm_sgbuf_t; /* for magic cast */
/*
* return the pages matching with the given byte size
*/
static inline unsigned int snd_pcm_sgbuf_pages(size_t size)
{
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
}
int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize);
int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream);
int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size);
int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream);
int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count);
void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
#endif /* __SOUND_PCM_SGBUF_H */
...@@ -61,6 +61,7 @@ static inline int _snd_magic_bad(void *obj, unsigned long magic) ...@@ -61,6 +61,7 @@ static inline int _snd_magic_bad(void *obj, unsigned long magic)
#define snd_pcm_proc_private_t_magic 0xa15a0104 #define snd_pcm_proc_private_t_magic 0xa15a0104
#define snd_pcm_oss_file_t_magic 0xa15a0105 #define snd_pcm_oss_file_t_magic 0xa15a0105
#define snd_mixer_oss_t_magic 0xa15a0106 #define snd_mixer_oss_t_magic 0xa15a0106
#define snd_pcm_sgbuf_t_magic 0xa15a0107
#define snd_info_private_data_t_magic 0xa15a0201 #define snd_info_private_data_t_magic 0xa15a0201
#define snd_ctl_file_t_magic 0xa15a0301 #define snd_ctl_file_t_magic 0xa15a0301
......
/* include/version.h. Generated automatically by configure. */ /* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc2" #define CONFIG_SND_VERSION "0.9.0rc2"
#define CONFIG_SND_DATE " (Wed Jul 17 10:56:41 2002 UTC)" #define CONFIG_SND_DATE " (Sat Jul 20 07:16:41 2002 UTC)"
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz> # Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz>
# #
export-objs := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o export-objs := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o \
pcm_sgbuf.o
snd-objs := sound.o init.o isadma.o memory.o info.o control.o misc.o \ snd-objs := sound.o init.o isadma.o memory.o info.o control.o misc.o \
device.o wrappers.o device.o wrappers.o
...@@ -12,7 +13,7 @@ snd-objs += sound_oss.o info_oss.o ...@@ -12,7 +13,7 @@ snd-objs += sound_oss.o info_oss.o
endif endif
snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
pcm_memory.o pcm_memory.o pcm_sgbuf.o
snd-rawmidi-objs := rawmidi.o snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o snd-timer-objs := timer.o
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define __NO_VERSION__ #define __NO_VERSION__
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/threads.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
......
...@@ -960,6 +960,26 @@ int snd_pcm_hw_constraint_step(snd_pcm_runtime_t *runtime, ...@@ -960,6 +960,26 @@ int snd_pcm_hw_constraint_step(snd_pcm_runtime_t *runtime,
var, -1); var, -1);
} }
static int snd_pcm_hw_rule_pow2(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule)
{
static int pow2_sizes[] = {
1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30
};
return snd_interval_list(hw_param_interval(params, rule->var),
sizeof(pow2_sizes)/sizeof(int), pow2_sizes, 0);
}
int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
unsigned int cond,
snd_pcm_hw_param_t var)
{
return snd_pcm_hw_rule_add(runtime, cond, var,
snd_pcm_hw_rule_pow2, NULL,
var, -1);
}
/* To use the same code we have in alsa-lib */ /* To use the same code we have in alsa-lib */
#define snd_pcm_t snd_pcm_substream_t #define snd_pcm_t snd_pcm_substream_t
...@@ -2364,6 +2384,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); ...@@ -2364,6 +2384,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
EXPORT_SYMBOL(snd_pcm_hw_rule_add); EXPORT_SYMBOL(snd_pcm_hw_rule_add);
EXPORT_SYMBOL(snd_pcm_set_ops); EXPORT_SYMBOL(snd_pcm_set_ops);
EXPORT_SYMBOL(snd_pcm_set_sync); EXPORT_SYMBOL(snd_pcm_set_sync);
......
...@@ -2631,6 +2631,7 @@ static unsigned long snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsig ...@@ -2631,6 +2631,7 @@ static unsigned long snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsig
snd_pcm_runtime_t *runtime; snd_pcm_runtime_t *runtime;
unsigned long offset; unsigned long offset;
struct page * page; struct page * page;
void *vaddr;
size_t dma_bytes; size_t dma_bytes;
if (substream == NULL) if (substream == NULL)
...@@ -2646,7 +2647,13 @@ static unsigned long snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsig ...@@ -2646,7 +2647,13 @@ static unsigned long snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsig
dma_bytes = PAGE_ALIGN(runtime->dma_bytes); dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
if (offset > dma_bytes - PAGE_SIZE) if (offset > dma_bytes - PAGE_SIZE)
return NOPAGE_SIGBUS; return NOPAGE_SIGBUS;
page = virt_to_page(runtime->dma_area + offset); if (substream->ops->page) {
vaddr = substream->ops->page(substream, offset);
if (! vaddr)
return NOPAGE_OOM;
} else
vaddr = runtime->dma_area + offset;
page = virt_to_page(vaddr);
get_page(page); get_page(page);
#ifndef LINUX_2_2 #ifndef LINUX_2_2
return page; return page;
......
/*
* Scatter-Gather PCM access
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define __NO_VERSION__
#include <sound/driver.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_sgbuf.h>
/* table entries are align to 32 */
#define SGBUF_TBL_ALIGN 32
#define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
/*
* shrink to the given pages.
* free the unused pages
*/
static void sgbuf_shrink(struct snd_sg_buf *sgbuf, int pages)
{
snd_assert(sgbuf, return);
if (! sgbuf->table)
return;
while (sgbuf->pages > pages) {
sgbuf->pages--;
snd_free_pci_pages(sgbuf->pci, PAGE_SIZE,
sgbuf->table[sgbuf->pages].buf,
sgbuf->table[sgbuf->pages].addr);
}
}
/*
* initialize the sg buffer
* assigned to substream->dma_private.
* initialize the table with the given size.
*/
int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize)
{
struct snd_sg_buf *sgbuf;
tblsize = sgbuf_align_table(tblsize);
sgbuf = snd_magic_kcalloc(snd_pcm_sgbuf_t, 0, GFP_KERNEL);
if (! sgbuf)
return -ENOMEM;
substream->dma_private = sgbuf;
sgbuf->pci = pci;
sgbuf->pages = 0;
sgbuf->tblsize = tblsize;
sgbuf->table = kmalloc(sizeof(struct snd_sg_page) * tblsize, GFP_KERNEL);
if (! sgbuf->table) {
snd_pcm_sgbuf_free(substream);
return -ENOMEM;
}
memset(sgbuf->table, 0, sizeof(struct snd_sg_page) * tblsize);
return 0;
}
/*
* release all pages and free the sgbuf instance
*/
int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream)
{
struct snd_sg_buf *sgbuf;
sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
sgbuf_shrink(sgbuf, 0);
if (sgbuf->table)
kfree(sgbuf->table);
snd_magic_kfree(sgbuf);
substream->dma_private = NULL;
return 0;
}
/*
* allocate sg buffer table with the given byte size.
* if the buffer table already exists, try to resize it.
* call this from hw_params callback.
*/
int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size)
{
struct snd_sg_buf *sgbuf;
unsigned int pages;
unsigned int tblsize;
int changed = 0;
sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
pages = snd_pcm_sgbuf_pages(size);
tblsize = sgbuf_align_table(pages);
if (pages < sgbuf->pages) {
/* release unsed pages */
sgbuf_shrink(sgbuf, pages);
substream->runtime->dma_bytes = size;
return 1; /* changed */
} else if (pages > sgbuf->tblsize) {
/* bigger than existing one. reallocate the table. */
struct snd_sg_page *table;
table = kmalloc(sizeof(*table) * tblsize, GFP_KERNEL);
if (! table)
return -ENOMEM;
memcpy(table, sgbuf->table, sizeof(*table) * sgbuf->tblsize);
kfree(sgbuf->table);
sgbuf->table = table;
sgbuf->tblsize = tblsize;
}
/* allocate each page */
while (sgbuf->pages < pages) {
void *ptr;
dma_addr_t addr;
ptr = snd_malloc_pci_pages(sgbuf->pci, PAGE_SIZE, &addr);
if (! ptr)
return -ENOMEM;
sgbuf->table[sgbuf->pages].buf = ptr;
sgbuf->table[sgbuf->pages].addr = addr;
sgbuf->pages++;
changed = 1;
}
sgbuf->size = size;
substream->runtime->dma_bytes = size;
return changed;
}
/*
* free the sg buffer
* the table is kept.
* call this from hw_free callback.
*/
int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream)
{
struct snd_sg_buf *sgbuf;
sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
sgbuf_shrink(sgbuf, 0);
return 0;
}
/*
* get the page pointer on the given offset
* used as the page callback of pcm ops
*/
void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
{
struct snd_sg_buf *sgbuf;
unsigned int idx;
sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return NULL);
idx = offset >> PAGE_SHIFT;
if (idx >= sgbuf->pages)
return 0;
return sgbuf->table[idx].buf;
}
/*
* do copy_from_user to the sg buffer
*/
static int copy_from_user_sg_buf(snd_pcm_substream_t *substream,
char *buf, size_t hwoff, ssize_t bytes)
{
int len;
char *addr;
size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
hwoff -= p;
len = PAGE_SIZE - hwoff;
for (;;) {
addr = snd_pcm_sgbuf_ops_page(substream, p);
if (! addr)
return -EFAULT;
if (len > bytes)
len = bytes;
if (copy_from_user(addr + hwoff, buf, len))
return -EFAULT;
bytes -= len;
if (bytes <= 0)
break;
buf += len;
p += PAGE_SIZE;
len = PAGE_SIZE;
hwoff = 0;
}
return 0;
}
/*
* do copy_to_user from the sg buffer
*/
static int copy_to_user_sg_buf(snd_pcm_substream_t *substream,
char *buf, size_t hwoff, ssize_t bytes)
{
int len;
char *addr;
size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
hwoff -= p;
len = PAGE_SIZE - hwoff;
for (;;) {
addr = snd_pcm_sgbuf_ops_page(substream, p);
if (! addr)
return -EFAULT;
if (len > bytes)
len = bytes;
if (copy_to_user(buf, addr + hwoff, len))
return -EFAULT;
bytes -= len;
if (bytes <= 0)
break;
buf += len;
p += PAGE_SIZE;
len = PAGE_SIZE;
hwoff = 0;
}
return 0;
}
/*
* set silence on the sg buffer
*/
static int set_silence_sg_buf(snd_pcm_substream_t *substream,
size_t hwoff, ssize_t samples)
{
snd_pcm_runtime_t *runtime = substream->runtime;
int len, page_len;
char *addr;
size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
hwoff -= p;
len = bytes_to_samples(substream->runtime, PAGE_SIZE - hwoff);
page_len = bytes_to_samples(substream->runtime, PAGE_SIZE);
for (;;) {
addr = snd_pcm_sgbuf_ops_page(substream, p);
if (! addr)
return -EFAULT;
if (len > samples)
len = samples;
snd_pcm_format_set_silence(runtime->format, addr + hwoff, len);
samples -= len;
if (samples <= 0)
break;
p += PAGE_SIZE;
len = page_len;
hwoff = 0;
}
return 0;
}
/*
* copy callback for playback pcm ops
*/
int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count)
{
snd_pcm_runtime_t *runtime = substream->runtime;
if (channel < 0) {
return copy_from_user_sg_buf(substream, buf, frames_to_bytes(runtime, hwoff), frames_to_bytes(runtime, count));
} else {
size_t dma_csize = runtime->dma_bytes / runtime->channels;
size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
return copy_from_user_sg_buf(substream, buf, c_ofs, samples_to_bytes(runtime, count));
}
}
/*
* copy callback for capture pcm ops
*/
int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count)
{
snd_pcm_runtime_t *runtime = substream->runtime;
if (channel < 0) {
return copy_to_user_sg_buf(substream, buf, frames_to_bytes(runtime, hwoff), frames_to_bytes(runtime, count));
} else {
size_t dma_csize = runtime->dma_bytes / runtime->channels;
size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
return copy_to_user_sg_buf(substream, buf, c_ofs, samples_to_bytes(runtime, count));
}
}
/*
* silence callback for pcm ops
*/
int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count)
{
snd_pcm_runtime_t *runtime = substream->runtime;
if (channel < 0) {
return set_silence_sg_buf(substream, frames_to_bytes(runtime, hwoff),
frames_to_bytes(runtime, count));
} else {
size_t dma_csize = runtime->dma_bytes / runtime->channels;
size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
return set_silence_sg_buf(substream, c_ofs, samples_to_bytes(runtime, count));
}
}
/*
* Exported symbols
*/
EXPORT_SYMBOL(snd_pcm_sgbuf_init);
EXPORT_SYMBOL(snd_pcm_sgbuf_delete);
EXPORT_SYMBOL(snd_pcm_sgbuf_alloc);
EXPORT_SYMBOL(snd_pcm_sgbuf_free);
EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy_playback);
EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy_capture);
EXPORT_SYMBOL(snd_pcm_sgbuf_ops_silence);
EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/threads.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/timer.h> #include <sound/timer.h>
......
...@@ -501,6 +501,8 @@ EXPORT_SYMBOL(snd_printd); ...@@ -501,6 +501,8 @@ EXPORT_SYMBOL(snd_printd);
#ifdef CONFIG_SND_DEBUG_MEMORY #ifdef CONFIG_SND_DEBUG_MEMORY
EXPORT_SYMBOL(snd_wrapper_kmalloc); EXPORT_SYMBOL(snd_wrapper_kmalloc);
EXPORT_SYMBOL(snd_wrapper_kfree); EXPORT_SYMBOL(snd_wrapper_kfree);
EXPORT_SYMBOL(snd_wrapper_vmalloc);
EXPORT_SYMBOL(snd_wrapper_vfree);
#endif #endif
#ifdef HACK_PCI_ALLOC_CONSISTENT #ifdef HACK_PCI_ALLOC_CONSISTENT
EXPORT_SYMBOL(snd_pci_hack_alloc_consistent); EXPORT_SYMBOL(snd_pci_hack_alloc_consistent);
......
...@@ -227,6 +227,8 @@ static struct isapnp_card_id snd_card_pnpids[] __devinitdata = { ...@@ -227,6 +227,8 @@ static struct isapnp_card_id snd_card_pnpids[] __devinitdata = {
ISAPNP_CS4232('C','S','C',0x4336,0x0000,0x0010,0x0003), ISAPNP_CS4232('C','S','C',0x4336,0x0000,0x0010,0x0003),
/* Typhoon Soundsystem PnP - CS4236B */ /* Typhoon Soundsystem PnP - CS4236B */
ISAPNP_CS4232('C','S','C',0x4536,0x0000,0x0010,0x0003), ISAPNP_CS4232('C','S','C',0x4536,0x0000,0x0010,0x0003),
/* Crystal CX4235-XQ3 EP - CS4235 */
ISAPNP_CS4232('C','S','C',0x4625,0x0100,0x0110,0x0103),
/* TerraTec AudioSystem EWS64XL - CS4236B */ /* TerraTec AudioSystem EWS64XL - CS4236B */
ISAPNP_CS4232('C','S','C',0xa836,0xa800,0xa810,0xa803), ISAPNP_CS4232('C','S','C',0xa836,0xa800,0xa810,0xa803),
/* TerraTec AudioSystem EWS64XL - CS4236B */ /* TerraTec AudioSystem EWS64XL - CS4236B */
......
...@@ -7,6 +7,10 @@ CONFIG_SND_CS46XX ...@@ -7,6 +7,10 @@ CONFIG_SND_CS46XX
CONFIG_SND_CS46XX_ACCEPT_VALID CONFIG_SND_CS46XX_ACCEPT_VALID
Say 'Y' to allow sample resolution for mmap() transfers. Say 'Y' to allow sample resolution for mmap() transfers.
Note: This can be also specified via module option snd_mmap_valid.
CONFIG_SND_CS4281
Say 'Y' or 'M' to include support for Cirrus Logic CS4281.
CONFIG_SND_EMU10K1 CONFIG_SND_EMU10K1
Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!, Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!,
......
...@@ -8,7 +8,7 @@ dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SN ...@@ -8,7 +8,7 @@ dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SN
if [ "$CONFIG_SND_CS46XX" != "n" ]; then if [ "$CONFIG_SND_CS46XX" != "n" ]; then
bool ' Cirrus Logic (Sound Fusion) MMAP support for OSS' CONFIG_SND_CS46XX_ACCEPT_VALID bool ' Cirrus Logic (Sound Fusion) MMAP support for OSS' CONFIG_SND_CS46XX_ACCEPT_VALID
fi fi
dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND dep_tristate 'Cirrus Logic CS4281' CONFIG_SND_CS4281 $CONFIG_SND
dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND
dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/emu10k1.h> #include <sound/emu10k1.h>
#include <sound/pcm_sgbuf.h>
#define chip_t emu10k1_t #define chip_t emu10k1_t
...@@ -358,13 +359,13 @@ static int snd_emu10k1_playback_hw_params(snd_pcm_substream_t * substream, ...@@ -358,13 +359,13 @@ static int snd_emu10k1_playback_hw_params(snd_pcm_substream_t * substream,
if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0) if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
return err; return err;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) if ((err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params))) < 0)
return err; return err;
if (err > 0) { /* change */ if (err > 0) { /* change */
snd_util_memblk_t *memblk; snd_util_memblk_t *memblk;
if (epcm->memblk != NULL) if (epcm->memblk != NULL)
snd_emu10k1_free_pages(emu, epcm->memblk); snd_emu10k1_free_pages(emu, epcm->memblk);
memblk = snd_emu10k1_alloc_pages(emu, runtime->dma_addr, runtime->dma_bytes); memblk = snd_emu10k1_alloc_pages(emu, (struct snd_sg_buf *)substream->dma_private);
if ((epcm->memblk = memblk) == NULL || ((emu10k1_memblk_t *)memblk)->mapped_page < 0) { if ((epcm->memblk = memblk) == NULL || ((emu10k1_memblk_t *)memblk)->mapped_page < 0) {
epcm->start_addr = 0; epcm->start_addr = 0;
return -ENOMEM; return -ENOMEM;
...@@ -400,7 +401,7 @@ static int snd_emu10k1_playback_hw_free(snd_pcm_substream_t * substream) ...@@ -400,7 +401,7 @@ static int snd_emu10k1_playback_hw_free(snd_pcm_substream_t * substream)
epcm->memblk = NULL; epcm->memblk = NULL;
epcm->start_addr = 0; epcm->start_addr = 0;
} }
snd_pcm_lib_free_pages(substream); snd_pcm_sgbuf_free(substream);
return 0; return 0;
} }
...@@ -778,6 +779,10 @@ static int snd_emu10k1_playback_open(snd_pcm_substream_t * substream) ...@@ -778,6 +779,10 @@ static int snd_emu10k1_playback_open(snd_pcm_substream_t * substream)
runtime->private_data = epcm; runtime->private_data = epcm;
runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_playback; runtime->hw = snd_emu10k1_playback;
if ((err = snd_pcm_sgbuf_init(substream, emu->pci, 32)) < 0) {
snd_magic_kfree(epcm);
return err;
}
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {
snd_magic_kfree(epcm); snd_magic_kfree(epcm);
return err; return err;
...@@ -804,6 +809,7 @@ static int snd_emu10k1_playback_close(snd_pcm_substream_t * substream) ...@@ -804,6 +809,7 @@ static int snd_emu10k1_playback_close(snd_pcm_substream_t * substream)
emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number]; emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number];
mix->epcm = NULL; mix->epcm = NULL;
snd_pcm_sgbuf_delete(substream);
snd_emu10k1_pcm_mixer_notify(emu->card, mix, 0); snd_emu10k1_pcm_mixer_notify(emu->card, mix, 0);
return 0; return 0;
} }
...@@ -942,6 +948,9 @@ static snd_pcm_ops_t snd_emu10k1_playback_ops = { ...@@ -942,6 +948,9 @@ static snd_pcm_ops_t snd_emu10k1_playback_ops = {
prepare: snd_emu10k1_playback_prepare, prepare: snd_emu10k1_playback_prepare,
trigger: snd_emu10k1_playback_trigger, trigger: snd_emu10k1_playback_trigger,
pointer: snd_emu10k1_playback_pointer, pointer: snd_emu10k1_playback_pointer,
copy: snd_pcm_sgbuf_ops_copy_playback,
silence: snd_pcm_sgbuf_ops_silence,
page: snd_pcm_sgbuf_ops_page,
}; };
static snd_pcm_ops_t snd_emu10k1_capture_ops = { static snd_pcm_ops_t snd_emu10k1_capture_ops = {
...@@ -959,7 +968,6 @@ static void snd_emu10k1_pcm_free(snd_pcm_t *pcm) ...@@ -959,7 +968,6 @@ static void snd_emu10k1_pcm_free(snd_pcm_t *pcm)
{ {
emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return); emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return);
emu->pcm = NULL; emu->pcm = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
} }
int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm) int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
...@@ -984,8 +992,6 @@ int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm) ...@@ -984,8 +992,6 @@ int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
strcpy(pcm->name, "EMU10K1"); strcpy(pcm->name, "EMU10K1");
emu->pcm = pcm; emu->pcm = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 128*1024);
if (rpcm) if (rpcm)
*rpcm = pcm; *rpcm = pcm;
......
...@@ -289,22 +289,19 @@ int snd_emu10k1_memblk_map(emu10k1_t *emu, emu10k1_memblk_t *blk) ...@@ -289,22 +289,19 @@ int snd_emu10k1_memblk_map(emu10k1_t *emu, emu10k1_memblk_t *blk)
* page allocation for DMA * page allocation for DMA
*/ */
snd_util_memblk_t * snd_util_memblk_t *
snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size) snd_emu10k1_alloc_pages(emu10k1_t *emu, struct snd_sg_buf *sgbuf)
{ {
snd_util_memhdr_t *hdr; snd_util_memhdr_t *hdr;
emu10k1_memblk_t *blk; emu10k1_memblk_t *blk;
int page, err; int page, err, idx;
snd_assert(emu, return NULL); snd_assert(emu, return NULL);
snd_assert(size > 0 && size < MAXPAGES * EMUPAGESIZE, return NULL); snd_assert(sgbuf->size > 0 && sgbuf->size < MAXPAGES * EMUPAGESIZE, return NULL);
hdr = emu->memhdr; hdr = emu->memhdr;
snd_assert(hdr, return NULL); snd_assert(hdr, return NULL);
if (!is_valid_page(addr))
return NULL;
down(&hdr->block_mutex); down(&hdr->block_mutex);
blk = search_empty(emu, size); blk = search_empty(emu, sgbuf->size);
if (blk == NULL) { if (blk == NULL) {
up(&hdr->block_mutex); up(&hdr->block_mutex);
return NULL; return NULL;
...@@ -312,10 +309,15 @@ snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size) ...@@ -312,10 +309,15 @@ snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size)
/* fill buffer addresses but pointers are not stored so that /* fill buffer addresses but pointers are not stored so that
* snd_free_pci_pages() is not called in in synth_free() * snd_free_pci_pages() is not called in in synth_free()
*/ */
for (page = blk->first_page; page <= blk->last_page; page++) { idx = 0;
for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
dma_addr_t addr = sgbuf->table[idx].addr;
if (! is_valid_page(addr)) {
up(&hdr->block_mutex);
return NULL;
}
emu->page_addr_table[page] = addr; emu->page_addr_table[page] = addr;
emu->page_ptr_table[page] = NULL; emu->page_ptr_table[page] = NULL;
addr += PAGE_SIZE;
} }
/* set PTB entries */ /* set PTB entries */
......
...@@ -482,7 +482,6 @@ static inline int hdsp_write_gain(hdsp_t *hdsp, unsigned int addr, unsigned shor ...@@ -482,7 +482,6 @@ static inline int hdsp_write_gain(hdsp_t *hdsp, unsigned int addr, unsigned shor
if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT)) { if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT)) {
return -1; return -1;
} }
hdsp_write (hdsp, HDSP_fifoData, ad); hdsp_write (hdsp, HDSP_fifoData, ad);
hdsp->mixer_matrix[addr] = data; hdsp->mixer_matrix[addr] = data;
...@@ -854,10 +853,7 @@ static int snd_hdsp_midi_output_write (hdsp_midi_t *hmidi) ...@@ -854,10 +853,7 @@ static int snd_hdsp_midi_output_write (hdsp_midi_t *hmidi)
} }
if (clear_timer && hmidi->istimer && --hmidi->istimer <= 0) { if (clear_timer && hmidi->istimer && --hmidi->istimer <= 0) {
printk ("removing timer because there is nothing to do\n"); del_timer(&hmidi->timer);
if (del_timer(&hmidi->timer)) {
printk ("not removed\n");
}
} }
} }
...@@ -956,16 +952,12 @@ static void snd_hdsp_midi_output_trigger(snd_rawmidi_substream_t * substream, in ...@@ -956,16 +952,12 @@ static void snd_hdsp_midi_output_trigger(snd_rawmidi_substream_t * substream, in
hmidi->timer.function = snd_hdsp_midi_output_timer; hmidi->timer.function = snd_hdsp_midi_output_timer;
hmidi->timer.data = (unsigned long) hmidi; hmidi->timer.data = (unsigned long) hmidi;
hmidi->timer.expires = 1 + jiffies; hmidi->timer.expires = 1 + jiffies;
printk ("add timer from output trigger\n");
add_timer(&hmidi->timer); add_timer(&hmidi->timer);
hmidi->istimer++; hmidi->istimer++;
} }
} else { } else {
if (hmidi->istimer && --hmidi->istimer <= 0) { if (hmidi->istimer && --hmidi->istimer <= 0) {
printk ("remove timer in trigger off\n"); del_timer (&hmidi->timer);
if (del_timer (&hmidi->timer)) {
printk ("not removed\n");
}
} }
} }
spin_unlock_irqrestore (&hmidi->lock, flags); spin_unlock_irqrestore (&hmidi->lock, flags);
...@@ -2635,7 +2627,7 @@ static int snd_hdsp_hw_rule_channels_rate(snd_pcm_hw_params_t *params, ...@@ -2635,7 +2627,7 @@ static int snd_hdsp_hw_rule_channels_rate(snd_pcm_hw_params_t *params,
integer: 1, integer: 1,
}; };
return snd_interval_refine(c, &t); return snd_interval_refine(c, &t);
} else if (r->max < 88200) { } else if (r->max < 64000) {
snd_interval_t t = { snd_interval_t t = {
min: hdsp->ss_channels, min: hdsp->ss_channels,
max: hdsp->ss_channels, max: hdsp->ss_channels,
...@@ -2654,14 +2646,14 @@ static int snd_hdsp_hw_rule_rate_channels(snd_pcm_hw_params_t *params, ...@@ -2654,14 +2646,14 @@ static int snd_hdsp_hw_rule_rate_channels(snd_pcm_hw_params_t *params,
snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
if (c->min >= hdsp->ss_channels) { if (c->min >= hdsp->ss_channels) {
snd_interval_t t = { snd_interval_t t = {
min: 44100, min: 32000,
max: 48000, max: 48000,
integer: 1, integer: 1,
}; };
return snd_interval_refine(r, &t); return snd_interval_refine(r, &t);
} else if (c->max <= hdsp->ds_channels) { } else if (c->max <= hdsp->ds_channels) {
snd_interval_t t = { snd_interval_t t = {
min: 88200, min: 64000,
max: 96000, max: 96000,
integer: 1, integer: 1,
}; };
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment