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)
- direct don't use plugins
- block force block mode (rvplayer)
- 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
echo "squake 0 0 disable" > /proc/asound/card0/pcm0c/oss
......
......@@ -29,7 +29,7 @@
#include <sound/asound.h>
/** 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
......@@ -604,6 +604,8 @@ struct sndrv_seq_remove_events {
/* misc. conditioning flags */
#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_addr addr; /* client/port numbers */
......@@ -620,7 +622,8 @@ struct sndrv_seq_port_info {
void *kernel; /* reserved for kernel use (must be NULL) */
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 {
SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */
SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */
SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */
SNDRV_HWDEP_IFACE_MIXART, /* Digigram miXart cards */
/* 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 {
......
......@@ -931,6 +931,7 @@ struct _snd_emu10k1 {
unsigned long port; /* I/O port number */
struct resource *res_port;
int APS: 1, /* APS flag */
no_ac97: 1, /* no AC'97 */
tos_link: 1; /* tos link detected */
unsigned int audigy; /* is Audigy? */
unsigned int revision; /* chip revision */
......
......@@ -30,7 +30,9 @@ struct _snd_pcm_oss_setup {
unsigned int disable:1,
direct:1,
block:1,
nonblock:1;
nonblock:1,
wholefrag:1,
nosilence:1;
unsigned int periods;
unsigned int period_size;
snd_pcm_oss_setup_t *next;
......
......@@ -95,7 +95,6 @@ typedef struct snd_sf_list {
int zone_locked; /* locked time for zone */
int sample_locked; /* locked time for sample */
snd_sf_callback_t callback; /* callback functions */
char sf_locked; /* font lock flag */
struct semaphore presets_mutex;
spinlock_t lock;
snd_util_memhdr_t *memhdr;
......
/* include/version.h. Generated by configure. */
#define CONFIG_SND_VERSION "0.9.5"
#define CONFIG_SND_DATE " (Mon Jul 21 08:59:59 2003 UTC)"
#define CONFIG_SND_VERSION "0.9.6"
#define CONFIG_SND_DATE " (Mon Jul 28 11:08:42 2003 UTC)"
......@@ -946,6 +946,25 @@ module_init(snd_mem_init)
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
*/
......
......@@ -454,8 +454,18 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
sw_params->sleep_min = 0;
sw_params->avail_min = runtime->period_size;
sw_params->xfer_align = 1;
sw_params->silence_threshold = 0;
sw_params->silence_size = 0;
if (atomic_read(&runtime->mmap_count) ||
(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) {
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
if (err < 0)
break;
runtime = substream->runtime;
if (*delay <= runtime->buffer_size)
if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size)
break;
/* in case of overrun, skip whole periods like OSS/Linux driver does */
/* until avail(delay) <= buffer_size */
......@@ -802,8 +812,9 @@ static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char *bu
buf += tmp;
bytes -= tmp;
xfer += tmp;
if (runtime->oss.buffer_used == runtime->oss.period_bytes) {
tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
if (substream->oss.setup == NULL || !substream->oss.setup->wholefrag ||
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)
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
runtime->oss.bytes += tmp;
......@@ -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;
down(&pstr->oss.setup_mutex);
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->periods,
setup->period_size,
setup->disable ? " disable" : "",
setup->direct ? " direct" : "",
setup->block ? " block" : "",
setup->nonblock ? " non-block" : "");
setup->nonblock ? " non-block" : "",
setup->wholefrag ? " whole-frag" : "",
setup->nosilence ? " no-silence" : "");
setup = setup->next;
}
up(&pstr->oss.setup_mutex);
......@@ -2181,6 +2194,10 @@ static void snd_pcm_oss_proc_write(snd_info_entry_t *entry,
template.block = 1;
} else if (!strcmp(str, "non-block")) {
template.nonblock = 1;
} else if (!strcmp(str, "whole-frag")) {
template.wholefrag = 1;
} else if (!strcmp(str, "no-silence")) {
template.nosilence = 1;
}
} while (*str);
if (setup == NULL) {
......@@ -2372,3 +2389,24 @@ static void __exit alsa_pcm_oss_exit(void)
module_init(alsa_pcm_oss_init)
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,
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)
{
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
plugin->buf = vmalloc(size);
plugin->buf_frames = frames;
}
if (!plugin->buf)
if (!plugin->buf) {
plugin->buf_frames = 0;
return -ENOMEM;
}
c = plugin->buf_channels;
if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
for (channel = 0; channel < format->channels; channel++, c++) {
c->frames = frames;
c->enabled = 1;
c->wanted = 0;
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
snd_assert((size % format->channels) == 0,);
size /= format->channels;
for (channel = 0; channel < format->channels; channel++, c++) {
c->frames = frames;
c->enabled = 1;
c->wanted = 0;
c->area.addr = plugin->buf + (channel * size);
......@@ -420,7 +435,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
/* Format change (linearization) */
if ((srcformat.format != dstformat.format ||
srcformat.rate != dstformat.rate ||
!rate_match(srcformat.rate, dstformat.rate) ||
srcformat.channels != dstformat.channels) &&
!snd_pcm_format_linear(srcformat.format)) {
if (snd_pcm_format_linear(dstformat.format))
......@@ -468,7 +483,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
ttable[v * sv + v] = FULL;
}
tmpformat.channels = dstformat.channels;
if (srcformat.rate == dstformat.rate &&
if (rate_match(srcformat.rate, dstformat.rate) &&
snd_pcm_format_linear(dstformat.format))
tmpformat.format = dstformat.format;
err = snd_pcm_plugin_build_route(plug,
......@@ -490,7 +505,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
}
/* rate resampling */
if (srcformat.rate != dstformat.rate) {
if (!rate_match(srcformat.rate, dstformat.rate)) {
tmpformat.rate = dstformat.rate;
if (srcformat.channels == dstformat.channels &&
snd_pcm_format_linear(dstformat.format))
......
......@@ -106,6 +106,7 @@ typedef struct _snd_pcm_channel_area {
typedef struct _snd_pcm_plugin_channel {
void *aptr; /* pointer to the allocated 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 wanted:1; /* channel is wanted */
} snd_pcm_plugin_channel_t;
......
......@@ -323,7 +323,7 @@ get_s16_1234_xxC3: sample = swab16(as_u32(src) ^ 0x80); goto GET_S16_END;
#ifdef PUT_S16_LABELS
/* 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_xxx9, /* 16h ^> 8h */
&&put_s16_xx12_xxx1, /* 16h -> 8s */
......
......@@ -85,11 +85,7 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
#undef PUT_S16_LABELS
void *get = get_s16_labels[data->get];
void *put = put_s16_labels[data->put];
void *get_s16_end = 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++) {
pos = data->pos;
......@@ -108,24 +104,16 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
dst_step = dst_channels[channel].area.step / 8;
src_frames1 = src_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) {
if (pos & ~R_MASK) {
pos &= R_MASK;
S1 = S2;
if (src_frames1-- > 0) {
get_s16_end = &&after_get2;
goto *get;
after_get2:
#define GET_S16_END after_get
#include "plugin_ops.h"
#undef GET_S16_END
after_get:
S2 = sample;
src += src_step;
}
......@@ -318,6 +306,8 @@ static snd_pcm_sframes_t rate_transfer(snd_pcm_plugin_t *plugin,
#endif
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->func(plugin, src_channels, dst_channels, frames, dst_frames);
return dst_frames;
......
......@@ -518,6 +518,10 @@ int getput_index(int format)
int sign, width, endian;
sign = !snd_pcm_format_signed(format);
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
endian = snd_pcm_format_big_endian(format);
#else
......
......@@ -60,13 +60,11 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
return;
snd_assert(runtime->silence_filled <= runtime->buffer_size, return);
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;
frames = runtime->silence_threshold - noise_dist;
if (frames > runtime->silence_size)
frames = runtime->silence_size;
else
frames = runtime->silence_threshold;
} else {
if (new_hw_ptr == ULONG_MAX) { /* initialization */
runtime->silence_filled = 0;
......@@ -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)
runtime->silence_start += runtime->boundary;
}
frames = runtime->buffer_size;
frames = runtime->buffer_size - runtime->silence_filled;
}
snd_assert(frames >= runtime->silence_filled, return);
frames -= runtime->silence_filled;
snd_assert(frames <= runtime->buffer_size, return);
if (frames == 0)
return;
ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size;
......
......@@ -22,6 +22,7 @@
#include <sound/driver.h>
#include <asm/io.h>
#include <linux/time.h>
#include <linux/init.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/info.h>
......@@ -568,3 +569,18 @@ struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned lon
}
#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_
if (params->xfer_align == 0 ||
params->xfer_align % runtime->min_align != 0)
return -EINVAL;
if ((params->silence_threshold != 0 || params->silence_size < runtime->boundary) &&
(params->silence_threshold + params->silence_size > runtime->buffer_size))
return -EINVAL;
if (params->silence_size >= runtime->boundary) {
if (params->silence_threshold != 0)
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);
runtime->tstamp_mode = params->tstamp_mode;
runtime->sleep_min = params->sleep_min;
......
......@@ -1630,6 +1630,26 @@ static void __exit alsa_rawmidi_exit(void)
module_init(alsa_rawmidi_init)
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_input_params);
EXPORT_SYMBOL(snd_rawmidi_drop_output);
......
......@@ -57,7 +57,7 @@ static struct _snd_timer_hardware rtc_hw = {
.stop = rtctimer_stop,
};
int rtctimer_freq = RTC_FREQ; /* frequency */
static int rtctimer_freq = RTC_FREQ; /* frequency */
static snd_timer_t *rtctimer;
static atomic_t rtc_inc = ATOMIC_INIT(0);
static rtc_task_t rtc_task;
......@@ -182,4 +182,16 @@ MODULE_PARM_DESC(rtctimer_freq, "timer frequency in Hz");
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 */
......@@ -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.
* if filter is non-zero, client filter bitmap is tested.
......@@ -551,6 +577,10 @@ static int snd_seq_deliver_single_event(client_t *client,
goto __skip;
}
if (dest_port->timestamping)
update_timestamp_of_queue(event, dest_port->time_queue,
dest_port->time_real);
/* expand the quoted event */
if (event->type == SNDRV_SEQ_EVENT_KERNEL_QUOTE) {
quoted = 1;
......@@ -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:
*/
......@@ -647,7 +656,10 @@ static int deliver_to_subscribers(client_t *client,
list_for_each(p, &grp->list_head) {
subs = list_entry(p, subscribers_t, src_list);
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,
0, atomic, hop);
if (err < 0)
......
......@@ -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->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;
}
......@@ -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->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;
}
......
......@@ -74,6 +74,9 @@ typedef struct client_port_t {
void *private_data;
unsigned int callback_all : 1;
unsigned int closing : 1;
unsigned int timestamping: 1;
unsigned int time_real: 1;
int time_queue;
/* capability, inport, output, sync */
unsigned int capability; /* port capability bits */
......
......@@ -389,6 +389,24 @@ static void __exit alsa_sound_exit(void)
module_init(alsa_sound_init)
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 */
EXPORT_SYMBOL(snd_major);
EXPORT_SYMBOL(snd_ecards_limit);
......
......@@ -41,7 +41,7 @@
#define DEFAULT_TIMER_LIMIT 2
#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_DESCRIPTION("ALSA timer interface");
MODULE_LICENSE("GPL");
......@@ -1806,6 +1806,18 @@ static void __exit alsa_timer_exit(void)
module_init(alsa_timer_init)
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_close);
EXPORT_SYMBOL(snd_timer_resolution);
......
......@@ -69,6 +69,15 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}");
#define USE_PERIODS_MAX 255
#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 */
#ifndef MAX_BUFFER_SIZE
......@@ -77,6 +86,11 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}");
#ifndef USE_FORMATS
#define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
#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
#define USE_CHANNELS_MIN 1
#endif
......@@ -271,9 +285,9 @@ static snd_pcm_hardware_t snd_card_dummy_playback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = USE_FORMATS,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5500,
.rate_max = 48000,
.rates = USE_RATE,
.rate_min = USE_RATE_MIN,
.rate_max = USE_RATE_MAX,
.channels_min = USE_CHANNELS_MIN,
.channels_max = USE_CHANNELS_MAX,
.buffer_bytes_max = MAX_BUFFER_SIZE,
......@@ -289,9 +303,9 @@ static snd_pcm_hardware_t snd_card_dummy_capture =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = USE_FORMATS,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5500,
.rate_max = 48000,
.rates = USE_RATE,
.rate_min = USE_RATE_MIN,
.rate_max = USE_RATE_MAX,
.channels_min = USE_CHANNELS_MIN,
.channels_max = USE_CHANNELS_MAX,
.buffer_bytes_max = MAX_BUFFER_SIZE,
......
......@@ -350,6 +350,18 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
#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,
struct pnp_card_link *pcard,
const struct pnp_card_device_id *pid)
......@@ -374,6 +386,7 @@ static int __init snd_sb16_probe(int dev,
if (card == NULL)
return -ENOMEM;
acard = (struct snd_card_sb16 *) card->private_data;
card->private_free = snd_sb16_free;
#ifdef CONFIG_PNP
if (isapnp[dev]) {
if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) {
......@@ -464,7 +477,8 @@ static int __init snd_sb16_probe(int dev,
if (fm_port[dev] > 0) {
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) {
snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
fm_port[dev], fm_port[dev] + 2);
......
......@@ -650,6 +650,26 @@ int patch_ad1881(ac97_t * ac97)
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)
{
unsigned short jack;
......@@ -661,6 +681,8 @@ int patch_ad1885(ac97_t * ac97)
/* turn off jack sense bits D8 & D9 */
jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF);
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300);
ac97->build_ops = &patch_ad1885_build_ops;
return 0;
}
......
......@@ -135,11 +135,9 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
snd_card_free(card);
return err;
}
if (!emu->APS) { /* APS board has not an AC97 mixer */
if ((err = snd_emu10k1_mixer(emu)) < 0) {
snd_card_free(card);
return err;
}
if ((err = snd_emu10k1_mixer(emu)) < 0) {
snd_card_free(card);
return err;
}
if (emu->audigy) {
if ((err = snd_emu10k1_audigy_midi(emu)) < 0) {
......
......@@ -674,6 +674,14 @@ int __devinit snd_emu10k1_create(snd_card_t * card,
if (emu->serial == 0x40011102) {
emu->card_type = EMU10K1_CARD_EMUAPS;
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;
......
......@@ -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)
{
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;
emu10k1_fx8010_code_t *icode;
emu10k1_fx8010_control_gpr_t *controls, *ctl;
......@@ -1261,19 +1264,15 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
strcpy(icode->name, "Audigy DSP code for ALSA");
ptr = 0;
nctl = 0;
playback = 10;
capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
gpr = capture + 10;
tmp = 0x88;
/* stop FX processor */
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+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr,
emu->revision == 4 ? 50 : 100);
snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
gpr += 2;
/* Wave Surround Playback */
......@@ -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);
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 */
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);
......@@ -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);
/* 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);
} else {
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)
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)
{
ac97_t ac97;
......@@ -430,7 +460,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
snd_kcontrol_t *kctl;
snd_card_t *card = emu->card;
if (!emu->APS) {
if (!emu->no_ac97) {
memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_emu10k1_ac97_write;
ac97.read = snd_emu10k1_ac97_read;
......@@ -438,8 +468,33 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
ac97.private_free = snd_emu10k1_mixer_free_ac97;
if ((err = snd_ac97_mixer(emu->card, &ac97, &emu->ac97)) < 0)
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 {
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)
......@@ -455,6 +510,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
if ((err = snd_ctl_add(card, kctl)))
return err;
/* intiailize the routing and volume table for each pcm playback stream */
for (pcm = 0; pcm < 32; pcm++) {
emu10k1_pcm_mixer_t *mix;
int v;
......@@ -474,21 +530,25 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
}
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
if (! emu->APS) { /* FIXME: APS has these controls? */
/* sb live! and audigy */
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
}
if (emu->audigy) {
if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
return -ENOMEM;
if ((err = snd_ctl_add(card, kctl)))
return err;
} else {
} else if (! emu->APS) {
/* sb live! */
if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
return -ENOMEM;
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)
if (status & IPR_CHANNELLOOP) {
int voice;
int voice_max = status & IPR_CHANNELNUMBERMASK;
int voice_max_l;
u32 val;
emu10k1_voice_t *pvoice = emu->voices;
val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
voice_max_l = voice_max;
if (voice_max_l >= 0x20)
voice_max_l = 0x1f;
for (voice = 0; voice <= voice_max_l; voice++) {
for (voice = 0; voice <= voice_max; voice++) {
if (voice == 0x20)
val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
if (val & 1) {
if (pvoice->use && pvoice->interrupt != NULL) {
pvoice->interrupt(emu, pvoice);
......@@ -75,21 +73,6 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
val >>= 1;
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_CHANNELNUMBERMASK;
......@@ -150,9 +133,27 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status &= ~IPR_FXDSP;
}
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);
}
......@@ -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;
static unsigned int i, rates[] = {
/* 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;
......@@ -1558,6 +1558,7 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
{ 0x1028, 0x0126, "Dell Optiplex GX260", AC97_TUNE_HP_ONLY },
{ 0x1734, 0x0088, "Fujitsu-Siemens D1522", 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 },
/* { 0x4144, 0x5360, "AMD64 Motherboard", AC97_TUNE_HP_ONLY }, */ /* FIXME: this seems invalid */
{ 0x1043, 0x80b0, "ASUS P4PE Mobo", AC97_TUNE_SWAP_SURROUND },
......
......@@ -1535,9 +1535,14 @@ static snd_pcm_uframes_t
snd_m3_pcm_pointer(snd_pcm_substream_t * subs)
{
m3_t *chip = snd_pcm_substream_chip(subs);
unsigned int ptr;
m3_dma_t *s = (m3_dma_t*)subs->runtime->private_data;
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)
snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, 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;
else
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)
fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
fmt |= runtime->channels << 4;
outb(fmt, VIADEV_REG(viadev, OFS_MULTPLAY_FORMAT));
if (chip->chip_type == TYPE_VIA8233A)
if (chip->revision == VIA_REV_8233A)
slots = 0;
else {
/* 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)
if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0)
return err;
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);
return 0;
}
......
......@@ -66,15 +66,11 @@ static void snd_sf_clear(snd_sf_list_t *sflist);
static int
lock_preset(snd_sf_list_t *sflist, int nonblock)
{
unsigned long flags;
spin_lock_irqsave(&sflist->lock, flags);
if (sflist->sf_locked && nonblock) {
spin_unlock_irqrestore(&sflist->lock, flags);
return -EBUSY;
}
spin_unlock_irqrestore(&sflist->lock, flags);
down(&sflist->presets_mutex);
sflist->sf_locked = 1;
if (nonblock) {
if (down_trylock(&sflist->presets_mutex))
return -EBUSY;
} else
down(&sflist->presets_mutex);
return 0;
}
......@@ -86,7 +82,6 @@ static void
unlock_preset(snd_sf_list_t *sflist)
{
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)
init_MUTEX(&sflist->presets_mutex);
spin_lock_init(&sflist->lock);
sflist->sf_locked = 0;
sflist->memhdr = hdr;
if (callback)
......@@ -1403,7 +1397,7 @@ snd_soundfont_remove_samples(snd_sf_list_t *sflist)
/*
* Remove unlocked samples.
* The soundcard should be silet before calling this function.
* The soundcard should be silent before calling this function.
*/
int
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)
*/
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
* 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