Commit 2efb2171 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA 0.9.6 update

  - added __setup() to all midlevel modules
  - sequencer protocol 1.0.1
    - added timestamping flags for ports
  - OSS PCM emulation
    - fixed write() behaviour
    - added two new options no-silence & whole-frag
    - a try to fix OOPSes caused in the rate plugin
  - emu10k1 driver
    - more support for Audigy/Audigy2 EX
    - fixed soundfont locking
  - sb16 driver
    - fixed fm_res handling (and proc OOPS)
  - via82xx driver
    - fixed revision check for 8233A
  - usbaudio driver
    - added a workaround for M-Audio Audiophile USB
parent 6b45ffcc
...@@ -1303,6 +1303,9 @@ Proc interfaces (/proc/asound) ...@@ -1303,6 +1303,9 @@ Proc interfaces (/proc/asound)
- direct don't use plugins - direct don't use plugins
- block force block mode (rvplayer) - block force block mode (rvplayer)
- non-block force non-block mode - non-block force non-block mode
- whole-frag write only whole fragments (optimization affecting
playback only)
- no-silence do not fill silence ahead to avoid clicks
Example: echo "x11amp 128 16384" > /proc/asound/card0/pcm0p/oss Example: echo "x11amp 128 16384" > /proc/asound/card0/pcm0p/oss
echo "squake 0 0 disable" > /proc/asound/card0/pcm0c/oss echo "squake 0 0 disable" > /proc/asound/card0/pcm0c/oss
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <sound/asound.h> #include <sound/asound.h>
/** version of the sequencer */ /** version of the sequencer */
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 0) #define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1)
/** /**
* definition of sequencer event types * definition of sequencer event types
...@@ -604,6 +604,8 @@ struct sndrv_seq_remove_events { ...@@ -604,6 +604,8 @@ struct sndrv_seq_remove_events {
/* misc. conditioning flags */ /* misc. conditioning flags */
#define SNDRV_SEQ_PORT_FLG_GIVEN_PORT (1<<0) #define SNDRV_SEQ_PORT_FLG_GIVEN_PORT (1<<0)
#define SNDRV_SEQ_PORT_FLG_TIMESTAMP (1<<1)
#define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<1)
struct sndrv_seq_port_info { struct sndrv_seq_port_info {
struct sndrv_seq_addr addr; /* client/port numbers */ struct sndrv_seq_addr addr; /* client/port numbers */
...@@ -620,7 +622,8 @@ struct sndrv_seq_port_info { ...@@ -620,7 +622,8 @@ struct sndrv_seq_port_info {
void *kernel; /* reserved for kernel use (must be NULL) */ void *kernel; /* reserved for kernel use (must be NULL) */
unsigned int flags; /* misc. conditioning */ unsigned int flags; /* misc. conditioning */
char reserved[60]; /* for future use */ unsigned char time_queue; /* queue # for timestamping */
char reserved[59]; /* for future use */
}; };
......
...@@ -105,9 +105,10 @@ enum sndrv_hwdep_iface { ...@@ -105,9 +105,10 @@ enum sndrv_hwdep_iface {
SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */ SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */
SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */ SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */
SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */ SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */
SNDRV_HWDEP_IFACE_MIXART, /* Digigram miXart cards */
/* Don't forget to change the following: */ /* Don't forget to change the following: */
SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_VX, SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_MIXART,
}; };
struct sndrv_hwdep_info { struct sndrv_hwdep_info {
......
...@@ -931,6 +931,7 @@ struct _snd_emu10k1 { ...@@ -931,6 +931,7 @@ struct _snd_emu10k1 {
unsigned long port; /* I/O port number */ unsigned long port; /* I/O port number */
struct resource *res_port; struct resource *res_port;
int APS: 1, /* APS flag */ int APS: 1, /* APS flag */
no_ac97: 1, /* no AC'97 */
tos_link: 1; /* tos link detected */ tos_link: 1; /* tos link detected */
unsigned int audigy; /* is Audigy? */ unsigned int audigy; /* is Audigy? */
unsigned int revision; /* chip revision */ unsigned int revision; /* chip revision */
......
...@@ -30,7 +30,9 @@ struct _snd_pcm_oss_setup { ...@@ -30,7 +30,9 @@ struct _snd_pcm_oss_setup {
unsigned int disable:1, unsigned int disable:1,
direct:1, direct:1,
block:1, block:1,
nonblock:1; nonblock:1,
wholefrag:1,
nosilence:1;
unsigned int periods; unsigned int periods;
unsigned int period_size; unsigned int period_size;
snd_pcm_oss_setup_t *next; snd_pcm_oss_setup_t *next;
......
...@@ -95,7 +95,6 @@ typedef struct snd_sf_list { ...@@ -95,7 +95,6 @@ typedef struct snd_sf_list {
int zone_locked; /* locked time for zone */ int zone_locked; /* locked time for zone */
int sample_locked; /* locked time for sample */ int sample_locked; /* locked time for sample */
snd_sf_callback_t callback; /* callback functions */ snd_sf_callback_t callback; /* callback functions */
char sf_locked; /* font lock flag */
struct semaphore presets_mutex; struct semaphore presets_mutex;
spinlock_t lock; spinlock_t lock;
snd_util_memhdr_t *memhdr; snd_util_memhdr_t *memhdr;
......
/* include/version.h. Generated by configure. */ /* include/version.h. Generated by configure. */
#define CONFIG_SND_VERSION "0.9.5" #define CONFIG_SND_VERSION "0.9.6"
#define CONFIG_SND_DATE " (Mon Jul 21 08:59:59 2003 UTC)" #define CONFIG_SND_DATE " (Mon Jul 28 11:08:42 2003 UTC)"
...@@ -946,6 +946,25 @@ module_init(snd_mem_init) ...@@ -946,6 +946,25 @@ module_init(snd_mem_init)
module_exit(snd_mem_exit) module_exit(snd_mem_exit)
#ifndef MODULE
/* format is: snd-page-alloc=enable */
static int __init snd_mem_setup(char *str)
{
static unsigned __initdata nr_dev = 0;
if (nr_dev >= SNDRV_CARDS)
return 0;
(void)(get_option(&str,&enable[nr_dev]) == 2);
nr_dev++;
return 1;
}
__setup("snd-page-alloc=", snd_mem_setup);
#endif
/* /*
* exports * exports
*/ */
......
...@@ -454,8 +454,18 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream) ...@@ -454,8 +454,18 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
sw_params->sleep_min = 0; sw_params->sleep_min = 0;
sw_params->avail_min = runtime->period_size; sw_params->avail_min = runtime->period_size;
sw_params->xfer_align = 1; sw_params->xfer_align = 1;
sw_params->silence_threshold = 0; if (atomic_read(&runtime->mmap_count) ||
sw_params->silence_size = 0; (substream->oss.setup && substream->oss.setup->nosilence)) {
sw_params->silence_threshold = 0;
sw_params->silence_size = 0;
} else {
snd_pcm_uframes_t frames;
frames = runtime->period_size + 16;
if (frames > runtime->buffer_size)
frames = runtime->buffer_size;
sw_params->silence_threshold = frames;
sw_params->silence_size = frames;
}
if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) { if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
snd_printd("SW_PARAMS failed: %i\n", err); snd_printd("SW_PARAMS failed: %i\n", err);
...@@ -581,7 +591,7 @@ static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, sn ...@@ -581,7 +591,7 @@ static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, sn
if (err < 0) if (err < 0)
break; break;
runtime = substream->runtime; runtime = substream->runtime;
if (*delay <= runtime->buffer_size) if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size)
break; break;
/* in case of overrun, skip whole periods like OSS/Linux driver does */ /* in case of overrun, skip whole periods like OSS/Linux driver does */
/* until avail(delay) <= buffer_size */ /* until avail(delay) <= buffer_size */
...@@ -802,8 +812,9 @@ static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char *bu ...@@ -802,8 +812,9 @@ static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char *bu
buf += tmp; buf += tmp;
bytes -= tmp; bytes -= tmp;
xfer += tmp; xfer += tmp;
if (runtime->oss.buffer_used == runtime->oss.period_bytes) { if (substream->oss.setup == NULL || !substream->oss.setup->wholefrag ||
tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); runtime->oss.buffer_used == runtime->oss.period_bytes) {
tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.buffer_used, 1);
if (tmp <= 0) if (tmp <= 0)
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
runtime->oss.bytes += tmp; runtime->oss.bytes += tmp;
...@@ -2108,14 +2119,16 @@ static void snd_pcm_oss_proc_read(snd_info_entry_t *entry, ...@@ -2108,14 +2119,16 @@ static void snd_pcm_oss_proc_read(snd_info_entry_t *entry,
snd_pcm_oss_setup_t *setup = pstr->oss.setup_list; snd_pcm_oss_setup_t *setup = pstr->oss.setup_list;
down(&pstr->oss.setup_mutex); down(&pstr->oss.setup_mutex);
while (setup) { while (setup) {
snd_iprintf(buffer, "%s %u %u%s%s%s%s\n", snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
setup->task_name, setup->task_name,
setup->periods, setup->periods,
setup->period_size, setup->period_size,
setup->disable ? " disable" : "", setup->disable ? " disable" : "",
setup->direct ? " direct" : "", setup->direct ? " direct" : "",
setup->block ? " block" : "", setup->block ? " block" : "",
setup->nonblock ? " non-block" : ""); setup->nonblock ? " non-block" : "",
setup->wholefrag ? " whole-frag" : "",
setup->nosilence ? " no-silence" : "");
setup = setup->next; setup = setup->next;
} }
up(&pstr->oss.setup_mutex); up(&pstr->oss.setup_mutex);
...@@ -2181,6 +2194,10 @@ static void snd_pcm_oss_proc_write(snd_info_entry_t *entry, ...@@ -2181,6 +2194,10 @@ static void snd_pcm_oss_proc_write(snd_info_entry_t *entry,
template.block = 1; template.block = 1;
} else if (!strcmp(str, "non-block")) { } else if (!strcmp(str, "non-block")) {
template.nonblock = 1; template.nonblock = 1;
} else if (!strcmp(str, "whole-frag")) {
template.wholefrag = 1;
} else if (!strcmp(str, "no-silence")) {
template.nosilence = 1;
} }
} while (*str); } while (*str);
if (setup == NULL) { if (setup == NULL) {
...@@ -2372,3 +2389,24 @@ static void __exit alsa_pcm_oss_exit(void) ...@@ -2372,3 +2389,24 @@ static void __exit alsa_pcm_oss_exit(void)
module_init(alsa_pcm_oss_init) module_init(alsa_pcm_oss_init)
module_exit(alsa_pcm_oss_exit) module_exit(alsa_pcm_oss_exit)
#ifndef MODULE
/* format is: snd-pcm-oss=dsp_map,adsp_map[,nonblock_open] */
static int __init alsa_pcm_oss_setup(char *str)
{
static unsigned __initdata nr_dev = 0;
if (nr_dev >= SNDRV_CARDS)
return 0;
(void)(get_option(&str,&dsp_map[nr_dev]) == 2 &&
get_option(&str,&adsp_map[nr_dev]) == 2);
(void)(get_option(&str,&nonblock_open) == 2);
nr_dev++;
return 1;
}
__setup("snd-pcm-oss=", alsa_pcm_oss_setup);
#endif /* !MODULE */
...@@ -56,6 +56,17 @@ static int snd_pcm_plugin_dst_channels_mask(snd_pcm_plugin_t *plugin, ...@@ -56,6 +56,17 @@ static int snd_pcm_plugin_dst_channels_mask(snd_pcm_plugin_t *plugin,
return 0; return 0;
} }
/*
* because some cards might have rates "very close", we ignore
* all "resampling" requests within +-5%
*/
static int rate_match(unsigned int src_rate, unsigned int dst_rate)
{
unsigned int low = (src_rate * 95) / 100;
unsigned int high = (src_rate * 105) / 100;
return dst_rate >= low && dst_rate <= high;
}
static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames) static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames)
{ {
snd_pcm_plugin_format_t *format; snd_pcm_plugin_format_t *format;
...@@ -80,11 +91,14 @@ static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t fram ...@@ -80,11 +91,14 @@ static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t fram
plugin->buf = vmalloc(size); plugin->buf = vmalloc(size);
plugin->buf_frames = frames; plugin->buf_frames = frames;
} }
if (!plugin->buf) if (!plugin->buf) {
plugin->buf_frames = 0;
return -ENOMEM; return -ENOMEM;
}
c = plugin->buf_channels; c = plugin->buf_channels;
if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
for (channel = 0; channel < format->channels; channel++, c++) { for (channel = 0; channel < format->channels; channel++, c++) {
c->frames = frames;
c->enabled = 1; c->enabled = 1;
c->wanted = 0; c->wanted = 0;
c->area.addr = plugin->buf; c->area.addr = plugin->buf;
...@@ -95,6 +109,7 @@ static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t fram ...@@ -95,6 +109,7 @@ static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t fram
snd_assert((size % format->channels) == 0,); snd_assert((size % format->channels) == 0,);
size /= format->channels; size /= format->channels;
for (channel = 0; channel < format->channels; channel++, c++) { for (channel = 0; channel < format->channels; channel++, c++) {
c->frames = frames;
c->enabled = 1; c->enabled = 1;
c->wanted = 0; c->wanted = 0;
c->area.addr = plugin->buf + (channel * size); c->area.addr = plugin->buf + (channel * size);
...@@ -420,7 +435,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug, ...@@ -420,7 +435,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
/* Format change (linearization) */ /* Format change (linearization) */
if ((srcformat.format != dstformat.format || if ((srcformat.format != dstformat.format ||
srcformat.rate != dstformat.rate || !rate_match(srcformat.rate, dstformat.rate) ||
srcformat.channels != dstformat.channels) && srcformat.channels != dstformat.channels) &&
!snd_pcm_format_linear(srcformat.format)) { !snd_pcm_format_linear(srcformat.format)) {
if (snd_pcm_format_linear(dstformat.format)) if (snd_pcm_format_linear(dstformat.format))
...@@ -468,7 +483,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug, ...@@ -468,7 +483,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
ttable[v * sv + v] = FULL; ttable[v * sv + v] = FULL;
} }
tmpformat.channels = dstformat.channels; tmpformat.channels = dstformat.channels;
if (srcformat.rate == dstformat.rate && if (rate_match(srcformat.rate, dstformat.rate) &&
snd_pcm_format_linear(dstformat.format)) snd_pcm_format_linear(dstformat.format))
tmpformat.format = dstformat.format; tmpformat.format = dstformat.format;
err = snd_pcm_plugin_build_route(plug, err = snd_pcm_plugin_build_route(plug,
...@@ -490,7 +505,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug, ...@@ -490,7 +505,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
} }
/* rate resampling */ /* rate resampling */
if (srcformat.rate != dstformat.rate) { if (!rate_match(srcformat.rate, dstformat.rate)) {
tmpformat.rate = dstformat.rate; tmpformat.rate = dstformat.rate;
if (srcformat.channels == dstformat.channels && if (srcformat.channels == dstformat.channels &&
snd_pcm_format_linear(dstformat.format)) snd_pcm_format_linear(dstformat.format))
......
...@@ -106,6 +106,7 @@ typedef struct _snd_pcm_channel_area { ...@@ -106,6 +106,7 @@ typedef struct _snd_pcm_channel_area {
typedef struct _snd_pcm_plugin_channel { typedef struct _snd_pcm_plugin_channel {
void *aptr; /* pointer to the allocated area */ void *aptr; /* pointer to the allocated area */
snd_pcm_channel_area_t area; snd_pcm_channel_area_t area;
snd_pcm_uframes_t frames; /* allocated frames */
unsigned int enabled:1; /* channel need to be processed */ unsigned int enabled:1; /* channel need to be processed */
unsigned int wanted:1; /* channel is wanted */ unsigned int wanted:1; /* channel is wanted */
} snd_pcm_plugin_channel_t; } snd_pcm_plugin_channel_t;
......
...@@ -323,7 +323,7 @@ get_s16_1234_xxC3: sample = swab16(as_u32(src) ^ 0x80); goto GET_S16_END; ...@@ -323,7 +323,7 @@ get_s16_1234_xxC3: sample = swab16(as_u32(src) ^ 0x80); goto GET_S16_END;
#ifdef PUT_S16_LABELS #ifdef PUT_S16_LABELS
/* dst_wid dst_endswap unsigned */ /* dst_wid dst_endswap unsigned */
static void *put_s16_labels[4 * 2 * 2 * 4 * 2] = { static void *put_s16_labels[4 * 2 * 2] = {
&&put_s16_xx12_xxx1, /* 16h -> 8h */ &&put_s16_xx12_xxx1, /* 16h -> 8h */
&&put_s16_xx12_xxx9, /* 16h ^> 8h */ &&put_s16_xx12_xxx9, /* 16h ^> 8h */
&&put_s16_xx12_xxx1, /* 16h -> 8s */ &&put_s16_xx12_xxx1, /* 16h -> 8s */
......
...@@ -85,11 +85,7 @@ static void resample_expand(snd_pcm_plugin_t *plugin, ...@@ -85,11 +85,7 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
#undef PUT_S16_LABELS #undef PUT_S16_LABELS
void *get = get_s16_labels[data->get]; void *get = get_s16_labels[data->get];
void *put = put_s16_labels[data->put]; void *put = put_s16_labels[data->put];
void *get_s16_end = 0;
signed short sample = 0; signed short sample = 0;
#define GET_S16_END *get_s16_end
#include "plugin_ops.h"
#undef GET_S16_END
for (channel = 0; channel < plugin->src_format.channels; channel++) { for (channel = 0; channel < plugin->src_format.channels; channel++) {
pos = data->pos; pos = data->pos;
...@@ -108,24 +104,16 @@ static void resample_expand(snd_pcm_plugin_t *plugin, ...@@ -108,24 +104,16 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
dst_step = dst_channels[channel].area.step / 8; dst_step = dst_channels[channel].area.step / 8;
src_frames1 = src_frames; src_frames1 = src_frames;
dst_frames1 = dst_frames; dst_frames1 = dst_frames;
if (pos & ~R_MASK) {
get_s16_end = &&after_get1;
goto *get;
after_get1:
pos &= R_MASK;
S1 = S2;
S2 = sample;
src += src_step;
src_frames1--;
}
while (dst_frames1-- > 0) { while (dst_frames1-- > 0) {
if (pos & ~R_MASK) { if (pos & ~R_MASK) {
pos &= R_MASK; pos &= R_MASK;
S1 = S2; S1 = S2;
if (src_frames1-- > 0) { if (src_frames1-- > 0) {
get_s16_end = &&after_get2;
goto *get; goto *get;
after_get2: #define GET_S16_END after_get
#include "plugin_ops.h"
#undef GET_S16_END
after_get:
S2 = sample; S2 = sample;
src += src_step; src += src_step;
} }
...@@ -318,6 +306,8 @@ static snd_pcm_sframes_t rate_transfer(snd_pcm_plugin_t *plugin, ...@@ -318,6 +306,8 @@ static snd_pcm_sframes_t rate_transfer(snd_pcm_plugin_t *plugin,
#endif #endif
dst_frames = rate_dst_frames(plugin, frames); dst_frames = rate_dst_frames(plugin, frames);
if (dst_frames > dst_channels[0].frames)
dst_frames = dst_channels[0].frames;
data = (rate_t *)plugin->extra_data; data = (rate_t *)plugin->extra_data;
data->func(plugin, src_channels, dst_channels, frames, dst_frames); data->func(plugin, src_channels, dst_channels, frames, dst_frames);
return dst_frames; return dst_frames;
......
...@@ -518,6 +518,10 @@ int getput_index(int format) ...@@ -518,6 +518,10 @@ int getput_index(int format)
int sign, width, endian; int sign, width, endian;
sign = !snd_pcm_format_signed(format); sign = !snd_pcm_format_signed(format);
width = snd_pcm_format_width(format) / 8 - 1; width = snd_pcm_format_width(format) / 8 - 1;
if (width < 0 || width > 3) {
snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
width = 0;
}
#ifdef SNDRV_LITTLE_ENDIAN #ifdef SNDRV_LITTLE_ENDIAN
endian = snd_pcm_format_big_endian(format); endian = snd_pcm_format_big_endian(format);
#else #else
......
...@@ -60,13 +60,11 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t ...@@ -60,13 +60,11 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
return; return;
snd_assert(runtime->silence_filled <= runtime->buffer_size, return); snd_assert(runtime->silence_filled <= runtime->buffer_size, return);
noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled; noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
if (noise_dist > (snd_pcm_sframes_t) runtime->silence_threshold) if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
return; return;
frames = runtime->silence_threshold - noise_dist; frames = runtime->silence_threshold - noise_dist;
if (frames > runtime->silence_size) if (frames > runtime->silence_size)
frames = runtime->silence_size; frames = runtime->silence_size;
else
frames = runtime->silence_threshold;
} else { } else {
if (new_hw_ptr == ULONG_MAX) { /* initialization */ if (new_hw_ptr == ULONG_MAX) { /* initialization */
runtime->silence_filled = 0; runtime->silence_filled = 0;
...@@ -86,10 +84,9 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t ...@@ -86,10 +84,9 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
if ((snd_pcm_sframes_t)runtime->silence_start < 0) if ((snd_pcm_sframes_t)runtime->silence_start < 0)
runtime->silence_start += runtime->boundary; runtime->silence_start += runtime->boundary;
} }
frames = runtime->buffer_size; frames = runtime->buffer_size - runtime->silence_filled;
} }
snd_assert(frames >= runtime->silence_filled, return); snd_assert(frames <= runtime->buffer_size, return);
frames -= runtime->silence_filled;
if (frames == 0) if (frames == 0)
return; return;
ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size; ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <asm/io.h> #include <asm/io.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/init.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/info.h> #include <sound/info.h>
...@@ -568,3 +569,18 @@ struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned lon ...@@ -568,3 +569,18 @@ struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned lon
} }
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
#ifndef MODULE
/* format is: snd-pcm=preallocate_dma,maximum_substreams */
static int __init alsa_pcm_setup(char *str)
{
(void)(get_option(&str,&preallocate_dma) == 2 &&
get_option(&str,&maximum_substreams) == 2);
return 1;
}
__setup("snd-pcm=", alsa_pcm_setup);
#endif /* ifndef MODULE */
...@@ -461,9 +461,15 @@ static int snd_pcm_sw_params(snd_pcm_substream_t * substream, snd_pcm_sw_params_ ...@@ -461,9 +461,15 @@ static int snd_pcm_sw_params(snd_pcm_substream_t * substream, snd_pcm_sw_params_
if (params->xfer_align == 0 || if (params->xfer_align == 0 ||
params->xfer_align % runtime->min_align != 0) params->xfer_align % runtime->min_align != 0)
return -EINVAL; return -EINVAL;
if ((params->silence_threshold != 0 || params->silence_size < runtime->boundary) && if (params->silence_size >= runtime->boundary) {
(params->silence_threshold + params->silence_size > runtime->buffer_size)) if (params->silence_threshold != 0)
return -EINVAL; return -EINVAL;
} else {
if (params->silence_size > params->silence_threshold)
return -EINVAL;
if (params->silence_threshold > runtime->buffer_size)
return -EINVAL;
}
snd_pcm_stream_lock_irq(substream); snd_pcm_stream_lock_irq(substream);
runtime->tstamp_mode = params->tstamp_mode; runtime->tstamp_mode = params->tstamp_mode;
runtime->sleep_min = params->sleep_min; runtime->sleep_min = params->sleep_min;
......
...@@ -1630,6 +1630,26 @@ static void __exit alsa_rawmidi_exit(void) ...@@ -1630,6 +1630,26 @@ static void __exit alsa_rawmidi_exit(void)
module_init(alsa_rawmidi_init) module_init(alsa_rawmidi_init)
module_exit(alsa_rawmidi_exit) module_exit(alsa_rawmidi_exit)
#ifndef MODULE
#ifdef CONFIG_SND_OSSEMUL
/* format is: snd-rawmidi=midi_map,amidi_map */
static int __init alsa_rawmidi_setup(char *str)
{
static unsigned __initdata nr_dev = 0;
if (nr_dev >= SNDRV_CARDS)
return 0;
(void)(get_option(&str,&midi_map[nr_dev]) == 2 &&
get_option(&str,&amidi_map[nr_dev]) == 2);
nr_dev++;
return 1;
}
__setup("snd-rawmidi=", alsa_rawmidi_setup);
#endif /* CONFIG_SND_OSSEMUL */
#endif /* ifndef MODULE */
EXPORT_SYMBOL(snd_rawmidi_output_params); EXPORT_SYMBOL(snd_rawmidi_output_params);
EXPORT_SYMBOL(snd_rawmidi_input_params); EXPORT_SYMBOL(snd_rawmidi_input_params);
EXPORT_SYMBOL(snd_rawmidi_drop_output); EXPORT_SYMBOL(snd_rawmidi_drop_output);
......
...@@ -57,7 +57,7 @@ static struct _snd_timer_hardware rtc_hw = { ...@@ -57,7 +57,7 @@ static struct _snd_timer_hardware rtc_hw = {
.stop = rtctimer_stop, .stop = rtctimer_stop,
}; };
int rtctimer_freq = RTC_FREQ; /* frequency */ static int rtctimer_freq = RTC_FREQ; /* frequency */
static snd_timer_t *rtctimer; static snd_timer_t *rtctimer;
static atomic_t rtc_inc = ATOMIC_INIT(0); static atomic_t rtc_inc = ATOMIC_INIT(0);
static rtc_task_t rtc_task; static rtc_task_t rtc_task;
...@@ -182,4 +182,16 @@ MODULE_PARM_DESC(rtctimer_freq, "timer frequency in Hz"); ...@@ -182,4 +182,16 @@ MODULE_PARM_DESC(rtctimer_freq, "timer frequency in Hz");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifndef MODULE
/* format is: snd-rtctimer=freq */
static int __init rtctimer_setup(char *str)
{
(void)(get_option(&str,&rtctimer_freq) == 2);
return 1;
}
__setup("snd-rtctimer=", rtctimer_setup);
#endif /* ifndef MODULE */
#endif /* CONFIG_RTC || CONFIG_RTC_MODULE */ #endif /* CONFIG_RTC || CONFIG_RTC_MODULE */
...@@ -520,6 +520,32 @@ static int bounce_error_event(client_t *client, snd_seq_event_t *event, ...@@ -520,6 +520,32 @@ static int bounce_error_event(client_t *client, snd_seq_event_t *event,
} }
/*
* rewrite the time-stamp of the event record with the curren time
* of the given queue.
* return non-zero if updated.
*/
static int update_timestamp_of_queue(snd_seq_event_t *event, int queue, int real_time)
{
queue_t *q;
q = queueptr(queue);
if (! q)
return 0;
event->queue = queue;
event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;
if (real_time) {
event->time.time = snd_seq_timer_get_cur_time(q->timer);
event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;
} else {
event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
event->flags |= SNDRV_SEQ_TIME_STAMP_TICK;
}
queuefree(q);
return 1;
}
/* /*
* deliver an event to the specified destination. * deliver an event to the specified destination.
* if filter is non-zero, client filter bitmap is tested. * if filter is non-zero, client filter bitmap is tested.
...@@ -551,6 +577,10 @@ static int snd_seq_deliver_single_event(client_t *client, ...@@ -551,6 +577,10 @@ static int snd_seq_deliver_single_event(client_t *client,
goto __skip; goto __skip;
} }
if (dest_port->timestamping)
update_timestamp_of_queue(event, dest_port->time_queue,
dest_port->time_real);
/* expand the quoted event */ /* expand the quoted event */
if (event->type == SNDRV_SEQ_EVENT_KERNEL_QUOTE) { if (event->type == SNDRV_SEQ_EVENT_KERNEL_QUOTE) {
quoted = 1; quoted = 1;
...@@ -597,27 +627,6 @@ static int snd_seq_deliver_single_event(client_t *client, ...@@ -597,27 +627,6 @@ static int snd_seq_deliver_single_event(client_t *client,
} }
static void snd_seq_subs_update_event_header(subscribers_t *subs, snd_seq_event_t *event)
{
if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) {
/* convert time according to flag with subscription */
queue_t *q;
q = queueptr(subs->info.queue);
if (q) {
event->queue = subs->info.queue;
event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;
if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL) {
event->time.time = snd_seq_timer_get_cur_time(q->timer);
event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;
} else {
event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
event->flags |= SNDRV_SEQ_TIME_STAMP_TICK;
}
queuefree(q);
}
}
}
/* /*
* send the event to all subscribers: * send the event to all subscribers:
*/ */
...@@ -647,7 +656,10 @@ static int deliver_to_subscribers(client_t *client, ...@@ -647,7 +656,10 @@ static int deliver_to_subscribers(client_t *client,
list_for_each(p, &grp->list_head) { list_for_each(p, &grp->list_head) {
subs = list_entry(p, subscribers_t, src_list); subs = list_entry(p, subscribers_t, src_list);
event->dest = subs->info.dest; event->dest = subs->info.dest;
snd_seq_subs_update_event_header(subs, event); if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
/* convert time according to flag with subscription */
update_timestamp_of_queue(event, subs->info.queue,
subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
err = snd_seq_deliver_single_event(client, event, err = snd_seq_deliver_single_event(client, event,
0, atomic, hop); 0, atomic, hop);
if (err < 0) if (err < 0)
......
...@@ -352,6 +352,11 @@ int snd_seq_set_port_info(client_port_t * port, snd_seq_port_info_t * info) ...@@ -352,6 +352,11 @@ int snd_seq_set_port_info(client_port_t * port, snd_seq_port_info_t * info)
port->midi_voices = info->midi_voices; port->midi_voices = info->midi_voices;
port->synth_voices = info->synth_voices; port->synth_voices = info->synth_voices;
/* timestamping */
port->timestamping = (info->flags & SNDRV_SEQ_PORT_FLG_TIMESTAMP) ? 1 : 0;
port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0;
port->time_queue = info->time_queue;
return 0; return 0;
} }
...@@ -378,6 +383,15 @@ int snd_seq_get_port_info(client_port_t * port, snd_seq_port_info_t * info) ...@@ -378,6 +383,15 @@ int snd_seq_get_port_info(client_port_t * port, snd_seq_port_info_t * info)
info->read_use = port->c_src.count; info->read_use = port->c_src.count;
info->write_use = port->c_dest.count; info->write_use = port->c_dest.count;
/* timestamping */
info->flags = 0;
if (port->timestamping) {
info->flags |= SNDRV_SEQ_PORT_FLG_TIMESTAMP;
if (port->time_real)
info->flags |= SNDRV_SEQ_PORT_FLG_TIME_REAL;
info->time_queue = port->time_queue;
}
return 0; return 0;
} }
......
...@@ -74,6 +74,9 @@ typedef struct client_port_t { ...@@ -74,6 +74,9 @@ typedef struct client_port_t {
void *private_data; void *private_data;
unsigned int callback_all : 1; unsigned int callback_all : 1;
unsigned int closing : 1; unsigned int closing : 1;
unsigned int timestamping: 1;
unsigned int time_real: 1;
int time_queue;
/* capability, inport, output, sync */ /* capability, inport, output, sync */
unsigned int capability; /* port capability bits */ unsigned int capability; /* port capability bits */
......
...@@ -389,6 +389,24 @@ static void __exit alsa_sound_exit(void) ...@@ -389,6 +389,24 @@ static void __exit alsa_sound_exit(void)
module_init(alsa_sound_init) module_init(alsa_sound_init)
module_exit(alsa_sound_exit) module_exit(alsa_sound_exit)
#ifndef MODULE
/* format is: snd=major,cards_limit[,device_mode] */
static int __init alsa_sound_setup(char *str)
{
(void)(get_option(&str,&major) == 2 &&
get_option(&str,&cards_limit) == 2);
#ifdef CONFIG_DEVFS_FS
(void)(get_option(&str,&device_mode) == 2);
#endif
return 1;
}
__setup("snd=", alsa_sound_setup);
#endif /* ifndef MODULE */
/* sound.c */ /* sound.c */
EXPORT_SYMBOL(snd_major); EXPORT_SYMBOL(snd_major);
EXPORT_SYMBOL(snd_ecards_limit); EXPORT_SYMBOL(snd_ecards_limit);
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
#define DEFAULT_TIMER_LIMIT 2 #define DEFAULT_TIMER_LIMIT 2
#endif #endif
int timer_limit = DEFAULT_TIMER_LIMIT; static int timer_limit = DEFAULT_TIMER_LIMIT;
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ALSA timer interface"); MODULE_DESCRIPTION("ALSA timer interface");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -1806,6 +1806,18 @@ static void __exit alsa_timer_exit(void) ...@@ -1806,6 +1806,18 @@ static void __exit alsa_timer_exit(void)
module_init(alsa_timer_init) module_init(alsa_timer_init)
module_exit(alsa_timer_exit) module_exit(alsa_timer_exit)
#ifndef MODULE
/* format is: snd-timer=timer_limit */
static int __init alsa_timer_setup(char *str)
{
(void)(get_option(&str,&timer_limit) == 2);
return 1;
}
__setup("snd-timer=", alsa_timer_setup);
#endif /* ifndef MODULE */
EXPORT_SYMBOL(snd_timer_open); EXPORT_SYMBOL(snd_timer_open);
EXPORT_SYMBOL(snd_timer_close); EXPORT_SYMBOL(snd_timer_close);
EXPORT_SYMBOL(snd_timer_resolution); EXPORT_SYMBOL(snd_timer_resolution);
......
...@@ -69,6 +69,15 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}"); ...@@ -69,6 +69,15 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}");
#define USE_PERIODS_MAX 255 #define USE_PERIODS_MAX 255
#endif #endif
#if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */
#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE
#define USE_CHANNELS_MIN 2
#define USE_CHANNELS_MAX 2
#define USE_RATE SNDRV_PCM_RATE_48000
#define USE_RATE_MIN 48000
#define USE_RATE_MAX 48000
#endif
/* defaults */ /* defaults */
#ifndef MAX_BUFFER_SIZE #ifndef MAX_BUFFER_SIZE
...@@ -77,6 +86,11 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}"); ...@@ -77,6 +86,11 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}");
#ifndef USE_FORMATS #ifndef USE_FORMATS
#define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
#endif #endif
#ifndef USE_RATE
#define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000
#define USE_RATE_MIN 5500
#define USE_RATE_MAX 48000
#endif
#ifndef USE_CHANNELS_MIN #ifndef USE_CHANNELS_MIN
#define USE_CHANNELS_MIN 1 #define USE_CHANNELS_MIN 1
#endif #endif
...@@ -271,9 +285,9 @@ static snd_pcm_hardware_t snd_card_dummy_playback = ...@@ -271,9 +285,9 @@ static snd_pcm_hardware_t snd_card_dummy_playback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID),
.formats = USE_FORMATS, .formats = USE_FORMATS,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rates = USE_RATE,
.rate_min = 5500, .rate_min = USE_RATE_MIN,
.rate_max = 48000, .rate_max = USE_RATE_MAX,
.channels_min = USE_CHANNELS_MIN, .channels_min = USE_CHANNELS_MIN,
.channels_max = USE_CHANNELS_MAX, .channels_max = USE_CHANNELS_MAX,
.buffer_bytes_max = MAX_BUFFER_SIZE, .buffer_bytes_max = MAX_BUFFER_SIZE,
...@@ -289,9 +303,9 @@ static snd_pcm_hardware_t snd_card_dummy_capture = ...@@ -289,9 +303,9 @@ static snd_pcm_hardware_t snd_card_dummy_capture =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID),
.formats = USE_FORMATS, .formats = USE_FORMATS,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rates = USE_RATE,
.rate_min = 5500, .rate_min = USE_RATE_MIN,
.rate_max = 48000, .rate_max = USE_RATE_MAX,
.channels_min = USE_CHANNELS_MIN, .channels_min = USE_CHANNELS_MIN,
.channels_max = USE_CHANNELS_MAX, .channels_max = USE_CHANNELS_MAX,
.buffer_bytes_max = MAX_BUFFER_SIZE, .buffer_bytes_max = MAX_BUFFER_SIZE,
......
...@@ -350,6 +350,18 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard, ...@@ -350,6 +350,18 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
#endif /* CONFIG_PNP */ #endif /* CONFIG_PNP */
static void snd_sb16_free(snd_card_t *card)
{
struct snd_card_sb16 *acard = (struct snd_card_sb16 *)card->private_data;
if (acard == NULL)
return;
if (acard->fm_res) {
release_resource(acard->fm_res);
kfree_nocheck(acard->fm_res);
}
}
static int __init snd_sb16_probe(int dev, static int __init snd_sb16_probe(int dev,
struct pnp_card_link *pcard, struct pnp_card_link *pcard,
const struct pnp_card_device_id *pid) const struct pnp_card_device_id *pid)
...@@ -374,6 +386,7 @@ static int __init snd_sb16_probe(int dev, ...@@ -374,6 +386,7 @@ static int __init snd_sb16_probe(int dev,
if (card == NULL) if (card == NULL)
return -ENOMEM; return -ENOMEM;
acard = (struct snd_card_sb16 *) card->private_data; acard = (struct snd_card_sb16 *) card->private_data;
card->private_free = snd_sb16_free;
#ifdef CONFIG_PNP #ifdef CONFIG_PNP
if (isapnp[dev]) { if (isapnp[dev]) {
if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) { if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) {
...@@ -464,7 +477,8 @@ static int __init snd_sb16_probe(int dev, ...@@ -464,7 +477,8 @@ static int __init snd_sb16_probe(int dev,
if (fm_port[dev] > 0) { if (fm_port[dev] > 0) {
if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
OPL3_HW_OPL3, fm_port[dev] == port[dev], OPL3_HW_OPL3,
fm_port[dev] == port[dev] || fm_port[dev] == 0x388,
&opl3) < 0) { &opl3) < 0) {
snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n", snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
fm_port[dev], fm_port[dev] + 2); fm_port[dev], fm_port[dev] + 2);
......
...@@ -650,6 +650,26 @@ int patch_ad1881(ac97_t * ac97) ...@@ -650,6 +650,26 @@ int patch_ad1881(ac97_t * ac97)
return 0; return 0;
} }
static const snd_kcontrol_new_t snd_ac97_controls_ad1885[] = {
AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0),
AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0),
AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0),
AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0),
};
static int patch_ad1885_specific(ac97_t * ac97)
{
int err;
if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0)
return err;
return 0;
}
static struct snd_ac97_build_ops patch_ad1885_build_ops = {
.build_specific = &patch_ad1885_specific
};
int patch_ad1885(ac97_t * ac97) int patch_ad1885(ac97_t * ac97)
{ {
unsigned short jack; unsigned short jack;
...@@ -661,6 +681,8 @@ int patch_ad1885(ac97_t * ac97) ...@@ -661,6 +681,8 @@ int patch_ad1885(ac97_t * ac97)
/* turn off jack sense bits D8 & D9 */ /* turn off jack sense bits D8 & D9 */
jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF); jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF);
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300); snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300);
ac97->build_ops = &patch_ad1885_build_ops;
return 0; return 0;
} }
......
...@@ -135,11 +135,9 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, ...@@ -135,11 +135,9 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
if (!emu->APS) { /* APS board has not an AC97 mixer */ if ((err = snd_emu10k1_mixer(emu)) < 0) {
if ((err = snd_emu10k1_mixer(emu)) < 0) { snd_card_free(card);
snd_card_free(card); return err;
return err;
}
} }
if (emu->audigy) { if (emu->audigy) {
if ((err = snd_emu10k1_audigy_midi(emu)) < 0) { if ((err = snd_emu10k1_audigy_midi(emu)) < 0) {
......
...@@ -674,6 +674,14 @@ int __devinit snd_emu10k1_create(snd_card_t * card, ...@@ -674,6 +674,14 @@ int __devinit snd_emu10k1_create(snd_card_t * card,
if (emu->serial == 0x40011102) { if (emu->serial == 0x40011102) {
emu->card_type = EMU10K1_CARD_EMUAPS; emu->card_type = EMU10K1_CARD_EMUAPS;
emu->APS = 1; emu->APS = 1;
emu->no_ac97 = 1; /* APS has no AC97 chip */
}
else if (emu->revision == 4 && emu->serial == 0x10051102) {
/* Audigy 2 EX has apparently no effective AC97 controls
* (for both input and output), so we skip the AC97 detections
*/
snd_printdd(KERN_INFO "Audigy2 EX is detected. skpping ac97.\n");
emu->no_ac97 = 1;
} }
emu->fx8010.fxbus_mask = 0x303f; emu->fx8010.fxbus_mask = 0x303f;
......
...@@ -1238,7 +1238,10 @@ static void __devinit snd_emu10k1_init_stereo_onoff_control(emu10k1_fx8010_contr ...@@ -1238,7 +1238,10 @@ static void __devinit snd_emu10k1_init_stereo_onoff_control(emu10k1_fx8010_contr
static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
{ {
int err, i, z, gpr, tmp, playback, capture, nctl; int err, i, z, gpr, nctl;
const int playback = 10;
const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
const int tmp = 0x88;
u32 ptr; u32 ptr;
emu10k1_fx8010_code_t *icode; emu10k1_fx8010_code_t *icode;
emu10k1_fx8010_control_gpr_t *controls, *ctl; emu10k1_fx8010_control_gpr_t *controls, *ctl;
...@@ -1261,19 +1264,15 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) ...@@ -1261,19 +1264,15 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
strcpy(icode->name, "Audigy DSP code for ALSA"); strcpy(icode->name, "Audigy DSP code for ALSA");
ptr = 0; ptr = 0;
nctl = 0; nctl = 0;
playback = 10;
capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
gpr = capture + 10; gpr = capture + 10;
tmp = 0x88;
/* stop FX processor */ /* stop FX processor */
snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
/* Wave Playback */ /* Wave Playback Volume */
A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
emu->revision == 4 ? 50 : 100);
gpr += 2; gpr += 2;
/* Wave Surround Playback */ /* Wave Surround Playback */
...@@ -1497,6 +1496,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) ...@@ -1497,6 +1496,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0); snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
gpr += 2; gpr += 2;
/* Master volume for audigy2 */
if (emu->revision == 4) {
A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS));
A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
gpr += 2;
}
/* digital outputs */ /* digital outputs */
A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
...@@ -1504,7 +1511,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) ...@@ -1504,7 +1511,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
/* analog speakers */ /* analog speakers */
if (emu->audigy && emu->revision == 4) { /* audigy2 */ if (emu->revision == 4) { /* audigy2 */
A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
} else { } else {
A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
......
...@@ -423,6 +423,36 @@ static void snd_emu10k1_mixer_free_ac97(ac97_t *ac97) ...@@ -423,6 +423,36 @@ static void snd_emu10k1_mixer_free_ac97(ac97_t *ac97)
emu->ac97 = NULL; emu->ac97 = NULL;
} }
/*
*/
static int remove_ctl(snd_card_t *card, const char *name)
{
snd_ctl_elem_id_t id;
memset(&id, 0, sizeof(id));
strcpy(id.name, name);
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_remove_id(card, &id);
}
static snd_kcontrol_t *ctl_find(snd_card_t *card, const char *name)
{
snd_ctl_elem_id_t sid;
memset(&sid, 0, sizeof(sid));
strcpy(sid.name, name);
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_find_id(card, &sid);
}
static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
{
snd_kcontrol_t *kctl = ctl_find(card, src);
if (kctl) {
strcpy(kctl->id.name, dst);
return 0;
}
return -ENOENT;
}
int __devinit snd_emu10k1_mixer(emu10k1_t *emu) int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
{ {
ac97_t ac97; ac97_t ac97;
...@@ -430,7 +460,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) ...@@ -430,7 +460,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
snd_kcontrol_t *kctl; snd_kcontrol_t *kctl;
snd_card_t *card = emu->card; snd_card_t *card = emu->card;
if (!emu->APS) { if (!emu->no_ac97) {
memset(&ac97, 0, sizeof(ac97)); memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_emu10k1_ac97_write; ac97.write = snd_emu10k1_ac97_write;
ac97.read = snd_emu10k1_ac97_read; ac97.read = snd_emu10k1_ac97_read;
...@@ -438,8 +468,33 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) ...@@ -438,8 +468,33 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
ac97.private_free = snd_emu10k1_mixer_free_ac97; ac97.private_free = snd_emu10k1_mixer_free_ac97;
if ((err = snd_ac97_mixer(emu->card, &ac97, &emu->ac97)) < 0) if ((err = snd_ac97_mixer(emu->card, &ac97, &emu->ac97)) < 0)
return err; return err;
if (emu->audigy && emu->revision == 4) {
/* Master/PCM controls on ac97 of Audigy2 has no effect */
/* FIXME: keep master volume/switch to be sure.
* once after we check that they play really no roles,
* they shall be removed.
*/
rename_ctl(card, "Master Playback Switch", "AC97 Master Playback Switch");
rename_ctl(card, "Master Playback Volume", "AC97 Master Playback Volume");
/* pcm controls are removed */
remove_ctl(card, "PCM Playback Switch");
remove_ctl(card, "PCM Playback Volume");
}
} else { } else {
strcpy(emu->card->mixername, "EMU APS"); if (emu->APS)
strcpy(emu->card->mixername, "EMU APS");
else if (emu->audigy)
strcpy(emu->card->mixername, "SB Audigy");
else
strcpy(emu->card->mixername, "Emu10k1");
}
if (emu->audigy && emu->revision == 4) {
/* Audigy2 and Audigy2 EX */
/* use the conventional names */
rename_ctl(card, "Wave Playback Volume", "PCM Playback Volume");
rename_ctl(card, "Wave Playback Volume", "PCM Capture Volume");
rename_ctl(card, "Wave Master Playback Volume", "Master Playback Volume");
} }
if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
...@@ -455,6 +510,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) ...@@ -455,6 +510,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
if ((err = snd_ctl_add(card, kctl))) if ((err = snd_ctl_add(card, kctl)))
return err; return err;
/* intiailize the routing and volume table for each pcm playback stream */
for (pcm = 0; pcm < 32; pcm++) { for (pcm = 0; pcm < 32; pcm++) {
emu10k1_pcm_mixer_t *mix; emu10k1_pcm_mixer_t *mix;
int v; int v;
...@@ -474,21 +530,25 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) ...@@ -474,21 +530,25 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
} }
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) if (! emu->APS) { /* FIXME: APS has these controls? */
return -ENOMEM; /* sb live! and audigy */
if ((err = snd_ctl_add(card, kctl))) if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
return err; return -ENOMEM;
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) if ((err = snd_ctl_add(card, kctl)))
return -ENOMEM; return err;
if ((err = snd_ctl_add(card, kctl))) if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
return err; return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
}
if (emu->audigy) { if (emu->audigy) {
if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
return -ENOMEM; return -ENOMEM;
if ((err = snd_ctl_add(card, kctl))) if ((err = snd_ctl_add(card, kctl)))
return err; return err;
} else { } else if (! emu->APS) {
/* sb live! */
if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
return -ENOMEM; return -ENOMEM;
if ((err = snd_ctl_add(card, kctl))) if ((err = snd_ctl_add(card, kctl)))
......
...@@ -55,15 +55,13 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -55,15 +55,13 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & IPR_CHANNELLOOP) { if (status & IPR_CHANNELLOOP) {
int voice; int voice;
int voice_max = status & IPR_CHANNELNUMBERMASK; int voice_max = status & IPR_CHANNELNUMBERMASK;
int voice_max_l;
u32 val; u32 val;
emu10k1_voice_t *pvoice = emu->voices; emu10k1_voice_t *pvoice = emu->voices;
val = snd_emu10k1_ptr_read(emu, CLIPL, 0); val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
voice_max_l = voice_max; for (voice = 0; voice <= voice_max; voice++) {
if (voice_max_l >= 0x20) if (voice == 0x20)
voice_max_l = 0x1f; val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
for (voice = 0; voice <= voice_max_l; voice++) {
if (val & 1) { if (val & 1) {
if (pvoice->use && pvoice->interrupt != NULL) { if (pvoice->use && pvoice->interrupt != NULL) {
pvoice->interrupt(emu, pvoice); pvoice->interrupt(emu, pvoice);
...@@ -75,21 +73,6 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -75,21 +73,6 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
val >>= 1; val >>= 1;
pvoice++; pvoice++;
} }
if (voice_max > 0x1f) {
val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
for (; voice <= voice_max; voice++) {
if(val & 1) {
if (pvoice->use && pvoice->interrupt != NULL) {
pvoice->interrupt(emu, pvoice);
snd_emu10k1_voice_intr_ack(emu, voice);
} else {
snd_emu10k1_voice_intr_disable(emu, voice);
}
}
val >>= 1;
pvoice++;
}
}
status &= ~IPR_CHANNELLOOP; status &= ~IPR_CHANNELLOOP;
} }
status &= ~IPR_CHANNELNUMBERMASK; status &= ~IPR_CHANNELNUMBERMASK;
...@@ -150,9 +133,27 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -150,9 +133,27 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status &= ~IPR_FXDSP; status &= ~IPR_FXDSP;
} }
if (status) { if (status) {
snd_printd(KERN_WARNING "emu10k1: unhandled interrupt: 0x%08x\n", status); unsigned int bits;
snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
//make sure any interrupts we don't handle are disabled:
bits = INTE_FXDSPENABLE |
INTE_PCIERRORENABLE |
INTE_VOLINCRENABLE |
INTE_VOLDECRENABLE |
INTE_MUTEENABLE |
INTE_MICBUFENABLE |
INTE_ADCBUFENABLE |
INTE_EFXBUFENABLE |
INTE_GPSPDIFENABLE |
INTE_CDSPDIFENABLE |
INTE_INTERVALTIMERENB |
INTE_MIDITXENABLE |
INTE_MIDIRXENABLE;
if (emu->audigy)
bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2;
snd_emu10k1_intr_disable(emu, bits);
} }
outl(orig_status, emu->port + IPR); /* ack */ outl(orig_status, emu->port + IPR); /* ack all */
} }
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
...@@ -1002,7 +1002,7 @@ static int snd_intel8x0_pcm_open(snd_pcm_substream_t * substream, ichdev_t *ichd ...@@ -1002,7 +1002,7 @@ static int snd_intel8x0_pcm_open(snd_pcm_substream_t * substream, ichdev_t *ichd
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
static unsigned int i, rates[] = { static unsigned int i, rates[] = {
/* ATTENTION: these values depend on the definition in pcm.h! */ /* ATTENTION: these values depend on the definition in pcm.h! */
5512, 8000, 11025, 16000, 22050, 32000, 44100, 480000 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000
}; };
int err; int err;
...@@ -1558,6 +1558,7 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { ...@@ -1558,6 +1558,7 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
{ 0x1028, 0x0126, "Dell Optiplex GX260", AC97_TUNE_HP_ONLY }, { 0x1028, 0x0126, "Dell Optiplex GX260", AC97_TUNE_HP_ONLY },
{ 0x1734, 0x0088, "Fujitsu-Siemens D1522", AC97_TUNE_HP_ONLY }, { 0x1734, 0x0088, "Fujitsu-Siemens D1522", AC97_TUNE_HP_ONLY },
{ 0x10f1, 0x2665, "Fujitsu-Siemens Celcius", AC97_TUNE_HP_ONLY }, { 0x10f1, 0x2665, "Fujitsu-Siemens Celcius", AC97_TUNE_HP_ONLY },
{ 0x110a, 0x0056, "Fujitsu-Siemens Scenic", AC97_TUNE_HP_ONLY },
{ 0x8086, 0x4d44, "Intel D850EMV2", AC97_TUNE_HP_ONLY }, { 0x8086, 0x4d44, "Intel D850EMV2", AC97_TUNE_HP_ONLY },
/* { 0x4144, 0x5360, "AMD64 Motherboard", AC97_TUNE_HP_ONLY }, */ /* FIXME: this seems invalid */ /* { 0x4144, 0x5360, "AMD64 Motherboard", AC97_TUNE_HP_ONLY }, */ /* FIXME: this seems invalid */
{ 0x1043, 0x80b0, "ASUS P4PE Mobo", AC97_TUNE_SWAP_SURROUND }, { 0x1043, 0x80b0, "ASUS P4PE Mobo", AC97_TUNE_SWAP_SURROUND },
......
...@@ -1535,9 +1535,14 @@ static snd_pcm_uframes_t ...@@ -1535,9 +1535,14 @@ static snd_pcm_uframes_t
snd_m3_pcm_pointer(snd_pcm_substream_t * subs) snd_m3_pcm_pointer(snd_pcm_substream_t * subs)
{ {
m3_t *chip = snd_pcm_substream_chip(subs); m3_t *chip = snd_pcm_substream_chip(subs);
unsigned int ptr;
m3_dma_t *s = (m3_dma_t*)subs->runtime->private_data; m3_dma_t *s = (m3_dma_t*)subs->runtime->private_data;
snd_assert(s != NULL, return 0); snd_assert(s != NULL, return 0);
return bytes_to_frames(subs->runtime, snd_m3_get_pointer(chip, s, subs));
spin_lock(&chip->reg_lock);
ptr = snd_m3_get_pointer(chip, s, subs);
spin_unlock(&chip->reg_lock);
return bytes_to_frames(subs->runtime, ptr);
} }
......
...@@ -886,7 +886,7 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream) ...@@ -886,7 +886,7 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream)
snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
} }
if (chip->chip_type == TYPE_VIA8233A) if (chip->revision == VIA_REV_8233A)
rbits = 0; rbits = 0;
else else
rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000; rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000;
...@@ -928,7 +928,7 @@ static int snd_via8233_multi_prepare(snd_pcm_substream_t *substream) ...@@ -928,7 +928,7 @@ static int snd_via8233_multi_prepare(snd_pcm_substream_t *substream)
fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT; fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
fmt |= runtime->channels << 4; fmt |= runtime->channels << 4;
outb(fmt, VIADEV_REG(viadev, OFS_MULTPLAY_FORMAT)); outb(fmt, VIADEV_REG(viadev, OFS_MULTPLAY_FORMAT));
if (chip->chip_type == TYPE_VIA8233A) if (chip->revision == VIA_REV_8233A)
slots = 0; slots = 0;
else { else {
/* set sample number to slot 3, 4, 7, 8, 6, 9 (for VIA8233/C,8235) */ /* set sample number to slot 3, 4, 7, 8, 6, 9 (for VIA8233/C,8235) */
...@@ -1108,7 +1108,7 @@ static int snd_via8233_multi_open(snd_pcm_substream_t * substream) ...@@ -1108,7 +1108,7 @@ static int snd_via8233_multi_open(snd_pcm_substream_t * substream)
if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0) if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0)
return err; return err;
substream->runtime->hw.channels_max = 6; substream->runtime->hw.channels_max = 6;
if (chip->chip_type == TYPE_VIA8233A) if (chip->revision == VIA_REV_8233A)
snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels); snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
return 0; return 0;
} }
......
...@@ -66,15 +66,11 @@ static void snd_sf_clear(snd_sf_list_t *sflist); ...@@ -66,15 +66,11 @@ static void snd_sf_clear(snd_sf_list_t *sflist);
static int static int
lock_preset(snd_sf_list_t *sflist, int nonblock) lock_preset(snd_sf_list_t *sflist, int nonblock)
{ {
unsigned long flags; if (nonblock) {
spin_lock_irqsave(&sflist->lock, flags); if (down_trylock(&sflist->presets_mutex))
if (sflist->sf_locked && nonblock) { return -EBUSY;
spin_unlock_irqrestore(&sflist->lock, flags); } else
return -EBUSY; down(&sflist->presets_mutex);
}
spin_unlock_irqrestore(&sflist->lock, flags);
down(&sflist->presets_mutex);
sflist->sf_locked = 1;
return 0; return 0;
} }
...@@ -86,7 +82,6 @@ static void ...@@ -86,7 +82,6 @@ static void
unlock_preset(snd_sf_list_t *sflist) unlock_preset(snd_sf_list_t *sflist)
{ {
up(&sflist->presets_mutex); up(&sflist->presets_mutex);
sflist->sf_locked = 0;
} }
...@@ -1356,7 +1351,6 @@ snd_sf_new(snd_sf_callback_t *callback, snd_util_memhdr_t *hdr) ...@@ -1356,7 +1351,6 @@ snd_sf_new(snd_sf_callback_t *callback, snd_util_memhdr_t *hdr)
init_MUTEX(&sflist->presets_mutex); init_MUTEX(&sflist->presets_mutex);
spin_lock_init(&sflist->lock); spin_lock_init(&sflist->lock);
sflist->sf_locked = 0;
sflist->memhdr = hdr; sflist->memhdr = hdr;
if (callback) if (callback)
...@@ -1403,7 +1397,7 @@ snd_soundfont_remove_samples(snd_sf_list_t *sflist) ...@@ -1403,7 +1397,7 @@ snd_soundfont_remove_samples(snd_sf_list_t *sflist)
/* /*
* Remove unlocked samples. * Remove unlocked samples.
* The soundcard should be silet before calling this function. * The soundcard should be silent before calling this function.
*/ */
int int
snd_soundfont_remove_unlocked(snd_sf_list_t *sflist) snd_soundfont_remove_unlocked(snd_sf_list_t *sflist)
......
...@@ -2297,6 +2297,14 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) ...@@ -2297,6 +2297,14 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
*/ */
fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE;
} }
/* workaround for M-Audio Audiophile USB */
if (dev->descriptor.idVendor == 0x0763 &&
dev->descriptor.idProduct == 0x2003) {
/* doesn't set the sample rate attribute, but supports it */
fp->attributes |= EP_CS_ATTR_SAMPLE_RATE;
}
/* /*
* plantronics headset and Griffin iMic have set adaptive-in * plantronics headset and Griffin iMic have set adaptive-in
* although it's really not... * although it's really not...
......
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