Commit bfc3f9b2 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA update

  - updated programmer's documentation
  - recoded PCM scatter-gather memory management
  - MPU401 - cleanups
  - CMI8330 - cleanups
  - EMU10K1 - Audigy2 update
  - ENS1371 - added surround support
  - USB - added more quirks and improved PCM constraint definitions
parent 1ae204fd
......@@ -94,6 +94,9 @@
<sect1><title>ISA DMA Helpers</title>
!Esound/core/isadma.c
</sect1>
<sect1><title>Other Helper Macros</title>
!Iinclude/sound/core.h
</sect1>
</chapter>
</book>
......@@ -3659,13 +3659,8 @@
</para>
<para>
Note that these callbacks are atomic unlike the callbacks of
control API since the ac97 middle-layer routine takes a
spinlock before calling these callbacks. Therefore you cannot
use mutex or schedule in them. However, these are never called
from interrupts unless you do by yourself.
Thus it's not necessarily protected with
<function>spin_lock_irqsave()</function> usually.
These callbacks are non-atomic like the callbacks of control API
unless they are called during suspend/resume phase.
</para>
<para>
......@@ -3679,22 +3674,22 @@
The <structfield>reset</structfield> callback is used to reset
the codec. If the chip requires a special way of reset, you can
define this callback.
This callback is atomic, since it can be called in the suspend
phase, too.
This callback must be atomic when it's called in the suspend
mode.
</para>
<para>
The <structfield>wait</structfield> callback is used for a
certain wait at the standard initialization of the codec. If the
chip requires the extra wait-time, define this callback.
This callback is non-atomic.
This callback is always non-atomic, because it's never called
in the resume mode.
</para>
<para>
The <structfield>init</structfield> callback is used for
additional initialization of the codec. This callback is called
after the reset phase, and should be atomic, since it's called
from the resume handler, too.
after the reset, and should be atomic in the resume mode.
</para>
</section>
......@@ -4462,13 +4457,12 @@
<para>
For creating the SG-buffer handler, call
<function>snd_pcm_sgbuf_init()</function> in the
<structfield>open</structfield> callback
of a pcm substream (or in the constructor of the pcm).
<function>snd_pcm_lib_preallocate_sg_pages()</function> or
<function>snd_pcm_lib_preallocate_sg_pages_for_all()</function>
in the PCM constructor like other PCI pre-allocator.
You need to pass the
<structname>pci_dev</structname> struct pointer of the chip
and the default table size (which can be changed
dynamically). The <type>snd_sg_buf_t</type> instance is created as
<structname>pci_dev</structname> struct pointer of the chip.
The <type>snd_sg_buf_t</type> instance is created as
substream-&gt;dma_private. You can cast
the pointer like:
......@@ -4483,41 +4477,29 @@
</para>
<para>
Then call <function>snd_pcm_sgbuf_alloc()</function> instead
of normal <function>snd_pcm_lib_malloc_pages()</function> in
<structfield>hw_params</structfield> callback. The SG-handler
will allocate single pages
and build the table on sgbuf-&gt;table. The pointer and the
physical address of each page is stored in this table. You can
get the physical address at a certain offset via
Then call <function>snd_pcm_lib_malloc_pages()</function>
in <structfield>hw_params</structfield> callback
as well as in the case of normal PCI buffer.
The SG-buffer handler will allocate the non-contiguous kernel
pages of the given size and map them onto the virtually contiguous
memory. The virtual pointer is addressed in runtime-&gt;dma_area.
The physical address (runtime-&gt;dma_addr) is set to zero,
because the buffer is physically non-contigous.
The physical address table is set up in sgbuf-&gt;table.
You can get the physical address at a certain offset via
<function>snd_pcm_sgbuf_get_addr()</function>.
</para>
<para>
When a SG-handler is used, you need to set
<function>snd_pcm_sgbuf_ops_copy_playback</function> and
<function>snd_pcm_ops_silence</function> as the
<structfield>copy</structfield> and the
<structfield>silence</structfield> callbacks, respectively.
All the jobs described in the previous section will be done
by these helper functions.
Also, the <structfield>page</structfield> callback must be set as
<function>snd_pcm_sgbuf_ops_page</function>.
<function>snd_pcm_sgbuf_ops_page</function> as
the <structfield>page</structfield> callback.
</para>
<para>
For releasing the data, call
<function>snd_pcm_sgbuf_free()</function> in the
<structfield>hw_free</structfield> callback, and call
<function>snd_pcm_sgbuf_delete()</function> in the
<structfield>close</structfield> callback (or in the destructor,
if <function>snd_pcm_sgbuf_init()</function> was called in the
constructor).
</para>
<para>
Note that you must not do pre-allocation if a SG-handler is used.
They conflict with each other.
<function>snd_pcm_lib_free_pages()</function> in the
<structfield>hw_free</structfield> callback as usual.
</para>
</section>
......@@ -4551,13 +4533,6 @@
</programlisting>
</informalexample>
</para>
<para>
You don't need <structfield>copy</structfield> and
<structfield>silence</structfield> callbacks in this case,
because the copy/set operations are available on the virtual
address.
</para>
</section>
</chapter>
......
......@@ -163,6 +163,11 @@ quake, send a command via echo like the following:
% echo "quake 0 0 direct" > /proc/asound/card0/pcm0p/oss
While quake wants only playback, you may append the second command
to notify driver that only this direction is about to be allocated:
% echo "quake 0 0 disable" > /proc/asound/card0/pcm0c/oss
The permission of proc files depend on the module options of snd.
As default it's set as root, so you'll likely need to be superuser for
sending the command above.
......
......@@ -357,13 +357,17 @@ void snd_verbose_printk(const char *file, int line, const char *format, ...);
#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
void snd_verbose_printd(const char *file, int line, const char *format, ...);
#endif
#if defined(CONFIG_SND_DEBUG) && !defined(CONFIG_SND_VERBOSE_PRINTK)
void snd_printd(const char *format, ...);
#endif
/* --- */
#ifdef CONFIG_SND_VERBOSE_PRINTK
/**
* snd_printk - printk wrapper
* @fmt: format string
*
* Works like print() but prints the file and the line of the caller
* when configured with CONFIG_SND_VERBOSE_PRINTK.
*/
#define snd_printk(fmt, args...) \
snd_verbose_printk(__FILE__, __LINE__, fmt ,##args)
#else
......@@ -376,15 +380,45 @@ void snd_printd(const char *format, ...);
#define __ASTRING__(x) #x
#ifdef CONFIG_SND_VERBOSE_PRINTK
/**
* snd_printd - debug printk
* @format: format string
*
* Compiled only when Works like snd_printk() for debugging purpose.
* Ignored when CONFIG_SND_DEBUG is not set.
*/
#define snd_printd(fmt, args...) \
snd_verbose_printd(__FILE__, __LINE__, fmt ,##args)
#else
#define snd_printd(fmt, args...) \
printk(fmt ,##args)
#endif
/**
* snd_assert - run-time assersion macro
* @expr: expression
* @args...: the action
*
* This macro checks the expression in run-time and invokes the commands
* given in the rest arguments if the assertion is failed.
* When CONFIG_SND_DEBUG is not set, the expression is executed but
* not checked.
*/
#define snd_assert(expr, args...) do {\
if (!(expr)) {\
snd_printk("BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
args;\
}\
} while (0)
/**
* snd_runtime_check - run-time assersion macro
* @expr: expression
* @args...: the action
*
* This macro checks the expression in run-time and invokes the commands
* given in the rest arguments if the assertion is failed.
* Unlike snd_assert(), the action commands are executed even if
* CONFIG_SND_DEBUG is not set but without any error messages.
*/
#define snd_runtime_check(expr, args...) do {\
if (!(expr)) {\
snd_printk("ERROR (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
......@@ -401,6 +435,13 @@ void snd_printd(const char *format, ...);
#endif /* CONFIG_SND_DEBUG */
#ifdef CONFIG_SND_DEBUG_DETECT
/**
* snd_printdd - debug printk
* @format: format string
*
* Compiled only when Works like snd_printk() for debugging purpose.
* Ignored when CONFIG_SND_DEBUG_DETECT is not set.
*/
#define snd_printdd(format, args...) snd_printk(format, ##args)
#else
#define snd_printdd(format, args...) /* nothing */
......
......@@ -231,7 +231,7 @@
#define A_IOCFG 0x18 /* GPIO on Audigy card (16bits) */
#define A_GPINPUT_MASK 0xff00
#define A_GPOUTPUT_MASK 0x00ff
#define A_IOCFG_GPOUT0 0x0040 /* analog/digital? */
#define A_IOCFG_GPOUT0 0x0044 /* analog/digital? */
#define TIMER 0x1a /* Timer terminal count register */
/* NOTE: After the rate is changed, a maximum */
......
......@@ -173,8 +173,9 @@ static inline snd_info_entry_t *snd_info_create_device(const char *name,
unsigned int mode) { return NULL; }
static inline void snd_info_free_device(snd_info_entry_t * entry) { ; }
static inline int snd_info_card_create(snd_card_t * card) { return 0; }
static inline int snd_info_card_register(snd_card_t * card) { return 0; }
static inline int snd_info_card_unregister(snd_card_t * card) { return 0; }
static inline int snd_info_card_free(snd_card_t * card) { return 0; }
static inline int snd_info_register(snd_info_entry_t * entry) { return 0; }
static inline int snd_info_unregister(snd_info_entry_t * entry) { return 0; }
......
......@@ -125,6 +125,7 @@ typedef struct _snd_pcm_ops {
#define SNDRV_PCM_DMA_TYPE_ISA 2 /* ISA continuous */
#define SNDRV_PCM_DMA_TYPE_PCI 3 /* PCI continuous */
#define SNDRV_PCM_DMA_TYPE_SBUS 4 /* SBUS continuous */
#define SNDRV_PCM_DMA_TYPE_PCI_SG 5 /* PCI SG-buffer */
/* If you change this don't forget to change rates[] table in pcm_native.c */
#define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
......@@ -743,6 +744,10 @@ int snd_pcm_hw_param_near(snd_pcm_substream_t *substream,
snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
unsigned int val, int *dir);
int snd_pcm_hw_param_set(snd_pcm_substream_t *pcm,
snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var,
unsigned int val, int dir);
int snd_pcm_hw_params_choose(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params);
int snd_pcm_hw_refine(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params);
......
......@@ -32,6 +32,7 @@ struct snd_sg_buf {
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table;
struct page **page_table;
struct pci_dev *pci;
};
......@@ -53,18 +54,17 @@ static inline dma_addr_t snd_pcm_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t
return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
}
int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize);
int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream);
int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size);
int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream);
struct snd_sg_buf *snd_pcm_sgbuf_init(struct pci_dev *pci);
void snd_pcm_sgbuf_delete(struct snd_sg_buf *sgbuf);
void *snd_pcm_sgbuf_alloc_pages(struct snd_sg_buf *sgbuf, size_t size);
int snd_pcm_sgbuf_free_pages(struct snd_sg_buf *sgbuf, void *vmaddr);
int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count);
struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci, snd_pcm_substream_t *substream);
int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci, snd_pcm_t *pcm);
#define _snd_pcm_substream_sgbuf(substream) ((substream)->dma_private)
#define snd_pcm_substream_sgbuf(substream) snd_magic_cast(snd_pcm_sgbuf_t, _snd_pcm_substream_sgbuf(substream), return -ENXIO)
struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
#endif /* __SOUND_PCM_SGBUF_H */
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc6"
#define CONFIG_SND_DATE " (Fri Jan 10 18:18:43 2003 UTC)"
#define CONFIG_SND_DATE " (Mon Jan 27 17:35:55 2003 UTC)"
......@@ -211,7 +211,8 @@ snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data)
kctl.id.iface = ncontrol->iface;
kctl.id.device = ncontrol->device;
kctl.id.subdevice = ncontrol->subdevice;
strncpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name)-1);
if (ncontrol->name)
strncpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name)-1);
kctl.id.index = ncontrol->index;
kctl.access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
(ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE|SNDRV_CTL_ELEM_ACCESS_INDIRECT));
......
......@@ -86,11 +86,19 @@ snd_card_t *snd_card_new(int idx, const char *xid,
idx = idx2;
break;
}
if (idx < 0 && snd_ecards_limit < SNDRV_CARDS)
/* for dynamically additional devices like hotplug:
* increment the limit if still free slot exists.
*/
idx = snd_ecards_limit++;
} else if (idx < snd_ecards_limit) {
if (snd_cards_lock & (1 << idx))
idx = -1; /* invalid */
}
if (idx < 0 || idx >= snd_ecards_limit) {
} else if (idx < SNDRV_CARDS)
snd_ecards_limit = idx + 1; /* increase the limit */
else
idx = -1;
if (idx < 0) {
write_unlock(&snd_card_rwlock);
if (idx >= snd_ecards_limit)
snd_printk(KERN_ERR "card %i is out of range (0-%i)\n", idx, snd_ecards_limit-1);
......
......@@ -251,6 +251,43 @@ static int snd_pcm_oss_period_size(snd_pcm_substream_t *substream,
return 0;
}
static int choose_rate(snd_pcm_substream_t *substream,
snd_pcm_hw_params_t *params, int best_rate)
{
snd_interval_t *it;
snd_pcm_hw_params_t *save;
int rate;
save = kmalloc(sizeof(*save), GFP_KERNEL);
if (save == NULL)
return -ENOMEM;
*save = *params;
it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE);
/* try multiples of the best rate */
rate = best_rate;
for (;;) {
if (it->max < rate || (it->max == rate && it->openmax))
break;
if (it->min < rate || (it->min == rate && !it->openmin)) {
int ret;
ret = snd_pcm_hw_param_set(substream, params,
SNDRV_PCM_HW_PARAM_RATE,
rate, 0);
if (ret == rate) {
kfree(save);
return rate;
}
*params = *save;
}
rate += best_rate;
}
/* not found, use the nearest rate */
kfree(save);
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, 0);
}
static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
......@@ -287,7 +324,7 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
snd_printd("No usable accesses\n");
return -EINVAL;
}
snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_RATE, runtime->oss.rate, 0);
choose_rate(substream, &sparams, runtime->oss.rate);
snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, 0);
format = snd_pcm_oss_format_from(runtime->oss.format);
......
......@@ -2578,6 +2578,7 @@ EXPORT_SYMBOL(snd_pcm_hw_param_mask);
EXPORT_SYMBOL(snd_pcm_hw_param_first);
EXPORT_SYMBOL(snd_pcm_hw_param_last);
EXPORT_SYMBOL(snd_pcm_hw_param_near);
EXPORT_SYMBOL(snd_pcm_hw_param_set);
EXPORT_SYMBOL(snd_pcm_hw_refine);
EXPORT_SYMBOL(snd_pcm_hw_constraints_init);
EXPORT_SYMBOL(snd_pcm_hw_constraints_complete);
......
......@@ -26,6 +26,9 @@
#include <sound/pcm.h>
#include <sound/info.h>
#include <sound/initval.h>
#ifdef CONFIG_PCI
#include <sound/pcm_sgbuf.h>
#endif
static int preallocate_dma = 1;
MODULE_PARM(preallocate_dma, "i");
......@@ -60,6 +63,10 @@ static int alloc_pcm_pages(snd_pcm_substream_t *substream, size_t size,
case SNDRV_PCM_DMA_TYPE_PCI:
*dma_area = snd_malloc_pci_pages((struct pci_dev *)substream->dma_private, size, dma_addr);
break;
case SNDRV_PCM_DMA_TYPE_PCI_SG:
*dma_area = snd_pcm_sgbuf_alloc_pages((struct snd_sg_buf *)substream->dma_private, size);
*dma_addr = 0;
break;
#endif
#ifdef CONFIG_SBUS
case SNDRV_PCM_DMA_TYPE_SBUS:
......@@ -121,6 +128,9 @@ static void free_pcm_pages(snd_pcm_substream_t *substream, size_t size,
snd_free_pci_pages((struct pci_dev *)substream->dma_private,
size, dma_area, dma_addr);
break;
case SNDRV_PCM_DMA_TYPE_PCI_SG:
snd_pcm_sgbuf_free_pages((struct snd_sg_buf *)substream->dma_private, dma_area);
break;
#endif
#ifdef CONFIG_SBUS
case SNDRV_PCM_DMA_TYPE_SBUS:
......@@ -158,6 +168,11 @@ int snd_pcm_lib_preallocate_free(snd_pcm_substream_t *substream)
snd_info_unregister(substream->proc_prealloc_entry);
substream->proc_prealloc_entry = NULL;
}
#ifdef CONFIG_PCI
if (substream->dma_type == SNDRV_PCM_DMA_TYPE_PCI_SG)
snd_pcm_sgbuf_delete((struct snd_sg_buf *)substream->dma_private);
#endif
substream->dma_type = SNDRV_PCM_DMA_TYPE_UNKNOWN;
return 0;
}
......
......@@ -1098,6 +1098,8 @@ static int snd_pcm_playback_drain(snd_pcm_substream_t * substream)
/* Fall through */
case SNDRV_PCM_STATE_SETUP:
goto _end;
default:
break;
}
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) {
......@@ -1200,6 +1202,8 @@ static int snd_pcm_playback_drop(snd_pcm_substream_t *substream)
spin_lock_irq(&runtime->lock);
}
goto _xrun_recovery;
default:
break;
}
runtime->control->appl_ptr = runtime->status->hw_ptr;
_end:
......@@ -1253,6 +1257,8 @@ static int snd_pcm_capture_drain(snd_pcm_substream_t * substream)
spin_lock_irq(&runtime->lock);
}
goto _xrun_recovery;
default:
break;
}
_end:
spin_unlock_irq(&runtime->lock);
......@@ -1295,6 +1301,8 @@ static int snd_pcm_capture_drop(snd_pcm_substream_t * substream)
case SNDRV_PCM_STATE_XRUN:
snd_pcm_change_state(substream, SNDRV_PCM_STATE_SETUP);
break;
default:
break;
}
runtime->control->appl_ptr = runtime->status->hw_ptr;
_end:
......
This diff is collapsed.
......@@ -90,7 +90,7 @@ void snd_request_card(int card)
read_unlock(&snd_card_rwlock);
if (locked)
return;
if (card < 0 || card >= snd_ecards_limit)
if (card < 0 || card >= cards_limit)
return;
sprintf(str, "snd-card-%i", card);
request_module(str);
......
......@@ -40,7 +40,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* MPU-401 port number */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* MPU-401 IRQ */
#ifdef CONFIG_PC9800
#ifdef CONFIG_X86_PC9800
static int pc98ii[SNDRV_CARDS]; /* PC98-II dauther board */
#endif
......@@ -59,7 +59,7 @@ MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device.");
MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
#ifdef CONFIG_PC9800
#ifdef CONFIG_X86_PC9800
MODULE_PARM(pc98ii, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(pc98ii, "Roland MPU-PC98II support.");
MODULE_PARM_SYNTAX(pc98ii, SNDRV_BOOLEAN_FALSE_DESC);
......@@ -85,7 +85,7 @@ static int __init snd_card_mpu401_probe(int dev)
if (card == NULL)
return -ENOMEM;
if (snd_mpu401_uart_new(card, 0,
#ifdef CONFIG_PC9800
#ifdef CONFIG_X86_PC9800
pc98ii[dev] ? MPU401_HW_PC98II :
#endif
MPU401_HW_MPU401,
......@@ -154,6 +154,9 @@ static int __init alsa_card_mpu401_setup(char *str)
(void)(get_option(&str,&enable[nr_dev]) == 2 &&
get_option(&str,&index[nr_dev]) == 2 &&
get_id(&str,&id[nr_dev]) == 2 &&
#ifdef CONFIG_X86_PC9800
get_option(&str,&pc98ii[nr_dev]) == 2 &&
#endif
get_option(&str,(int *)&port[nr_dev]) == 2 &&
get_option(&str,&irq[nr_dev]) == 2);
nr_dev++;
......
......@@ -65,13 +65,22 @@ static void snd_mpu401_uart_clear_rx(mpu401_t *mpu)
static void _snd_mpu401_uart_interrupt(mpu401_t *mpu)
{
if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
snd_mpu401_uart_input_read(mpu);
else
if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
if (! test_and_set_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode)) {
spin_lock(&mpu->input_lock);
snd_mpu401_uart_input_read(mpu);
spin_unlock(&mpu->input_lock);
clear_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode);
}
} else
snd_mpu401_uart_clear_rx(mpu);
/* ok. for better Tx performance try do some output when input is done */
if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode))
/* ok. for better Tx performance try do some output when input is done */
if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) &&
test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) {
spin_lock(&mpu->output_lock);
snd_mpu401_uart_output_write(mpu);
spin_unlock(&mpu->output_lock);
}
}
/**
......@@ -91,20 +100,26 @@ void snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
_snd_mpu401_uart_interrupt(mpu);
}
/*
* timer callback
* reprogram the timer and call the interrupt job
*/
static void snd_mpu401_uart_timer(unsigned long data)
{
unsigned long flags;
mpu401_t *mpu = snd_magic_cast(mpu401_t, (void *)data, return);
spin_lock_irqsave(&mpu->timer_lock, flags);
spin_lock(&mpu->timer_lock);
/*mpu->mode |= MPU401_MODE_TIMER;*/
mpu->timer.expires = 1 + jiffies;
add_timer(&mpu->timer);
spin_unlock_irqrestore(&mpu->timer_lock, flags);
spin_unlock(&mpu->timer_lock);
if (mpu->rmidi)
_snd_mpu401_uart_interrupt(mpu);
}
/*
* initialize the timer callback if not programmed yet
*/
static void snd_mpu401_uart_add_timer (mpu401_t *mpu, int input)
{
unsigned long flags;
......@@ -121,6 +136,9 @@ static void snd_mpu401_uart_add_timer (mpu401_t *mpu, int input)
spin_unlock_irqrestore (&mpu->timer_lock, flags);
}
/*
* remove the timer callback if still active
*/
static void snd_mpu401_uart_remove_timer (mpu401_t *mpu, int input)
{
unsigned long flags;
......@@ -244,7 +262,7 @@ static int snd_mpu401_uart_output_close(snd_rawmidi_substream_t * substream)
}
/*
* trigger input
* trigger input callback
*/
static void snd_mpu401_uart_input_trigger(snd_rawmidi_substream_t * substream, int up)
{
......@@ -253,48 +271,48 @@ static void snd_mpu401_uart_input_trigger(snd_rawmidi_substream_t * substream, i
int max = 64;
mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return);
spin_lock_irqsave(&mpu->input_lock, flags);
if (up) {
if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) {
/* flush FIFO */
/* first time - flush FIFO */
while (max-- > 0)
inb(MPU401D(mpu));
if (mpu->irq < 0)
snd_mpu401_uart_add_timer(mpu, 1);
}
/* read data in advance */
/* prevent double enter via rawmidi->event callback */
if (! test_and_set_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode)) {
spin_lock_irqsave(&mpu->input_lock, flags);
snd_mpu401_uart_input_read(mpu);
spin_unlock_irqrestore(&mpu->input_lock, flags);
clear_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode);
}
if (mpu->irq < 0)
snd_mpu401_uart_add_timer(mpu, 1);
} else {
if (mpu->irq < 0)
snd_mpu401_uart_remove_timer(mpu, 1);
clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
}
spin_unlock_irqrestore(&mpu->input_lock, flags);
if (up)
snd_mpu401_uart_input_read(mpu);
}
/*
* transfer input pending data
* call with input_lock spinlock held
*/
static void snd_mpu401_uart_input_read(mpu401_t * mpu)
{
int max = 128;
unsigned char byte;
/* prevent double enter via event callback */
if (test_and_set_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode))
return;
spin_lock(&mpu->input_lock);
while (max-- > 0) {
if (snd_mpu401_input_avail(mpu)) {
byte = inb(MPU401D(mpu));
if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) {
spin_unlock(&mpu->input_lock);
if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
snd_rawmidi_receive(mpu->substream_input, &byte, 1);
spin_lock(&mpu->input_lock);
}
} else {
break; /* input not available */
}
}
spin_unlock(&mpu->input_lock);
clear_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode);
}
/*
......@@ -305,18 +323,16 @@ static void snd_mpu401_uart_input_read(mpu401_t * mpu)
* SoundBlaster AWE 64 - 2 bytes (ugly hardware)
*/
/*
* write output pending bytes
* call with output_lock spinlock held
*/
static void snd_mpu401_uart_output_write(mpu401_t * mpu)
{
unsigned char byte;
int max = 256, timeout;
if (!test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode))
return;
/* prevent double enter */
if (test_and_set_bit(MPU401_MODE_BIT_TX_LOOP, &mpu->mode))
return;
do {
spin_lock(&mpu->output_lock);
if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) {
for (timeout = 100; timeout > 0; timeout--) {
if (snd_mpu401_output_ready(mpu)) {
......@@ -329,28 +345,38 @@ static void snd_mpu401_uart_output_write(mpu401_t * mpu)
snd_mpu401_uart_remove_timer (mpu, 0);
max = 1; /* no other data - leave the tx loop */
}
spin_unlock(&mpu->output_lock);
} while (--max > 0);
clear_bit(MPU401_MODE_BIT_TX_LOOP, &mpu->mode);
}
/*
* output trigger callback
*/
static void snd_mpu401_uart_output_trigger(snd_rawmidi_substream_t * substream, int up)
{
unsigned long flags;
mpu401_t *mpu;
mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return);
spin_lock_irqsave(&mpu->output_lock, flags);
if (up) {
set_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
/* try to add the timer at each output trigger,
* since the output timer might have been removed in
* snd_mpu401_uart_output_write().
*/
snd_mpu401_uart_add_timer(mpu, 0);
/* output pending data */
/* prevent double enter via rawmidi->event callback */
if (! test_and_set_bit(MPU401_MODE_BIT_TX_LOOP, &mpu->mode)) {
spin_lock_irqsave(&mpu->output_lock, flags);
snd_mpu401_uart_output_write(mpu);
spin_unlock_irqrestore(&mpu->output_lock, flags);
clear_bit(MPU401_MODE_BIT_TX_LOOP, &mpu->mode);
}
} else {
snd_mpu401_uart_remove_timer(mpu, 0);
clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
}
spin_unlock_irqrestore(&mpu->output_lock, flags);
if (up)
snd_mpu401_uart_output_write(mpu);
}
/*
......
......@@ -59,7 +59,7 @@
/*
*/
#define ENABLE_SB_MIXER
/* #define ENABLE_SB_MIXER */
#define PLAYBACK_ON_SB
/*
......@@ -209,7 +209,7 @@ AD1848_DOUBLE("Line Capture Volume", 0, CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0,
AD1848_DOUBLE("CD Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0),
AD1848_DOUBLE("CD Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0),
AD1848_DOUBLE("CD Playback Volume", 0, CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0),
AD1848_DOUBLE("CD Capture Switch", 0, CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0),
AD1848_DOUBLE("CD Capture Volume", 0, CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0),
AD1848_SINGLE("Mic Playback Switch", 0, CMI8330_MUTEMUX, 0, 1, 0),
AD1848_SINGLE("Mic Playback Volume", 0, CMI8330_OUTPUTVOL, 0, 7, 0),
AD1848_SINGLE("Mic Capture Switch", 0, CMI8330_RMUX3D, 0, 1, 0),
......
......@@ -204,6 +204,9 @@ static struct isapnp_card_id snd_sb16_pnpids[] __devinitdata = {
ISAPNP_SB16('C','T','L',0x0070,0x0001),
/* Sound Blaster Vibra16CL - added by ctm@ardi.com */
ISAPNP_SB16('C','T','L',0x0080,0x0041),
/* Sound Blaster 16 'value' PnP. It says model ct4130 on the pcb, */
/* but ct4131 on a sticker on the board.. */
ISAPNP_SB16('C','T','L',0x0086,0x0041),
/* Sound Blaster Vibra16X */
ISAPNP_SB16('C','T','L',0x00f0,0x0043),
#else /* SNDRV_SBAWE defined */
......
......@@ -141,7 +141,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x57454301, 0xffffffff, "W83971D", NULL },
{ 0x574d4c00, 0xffffffff, "WM9701A", patch_wolfson00 },
{ 0x574d4c03, 0xffffffff, "WM9703/9707", patch_wolfson03 },
{ 0x574d4c04, 0xffffffff, "WM9704 (quad)", patch_wolfson04 },
{ 0x574d4c04, 0xffffffff, "WM9704/quad", patch_wolfson04 },
{ 0x574d4c05, 0xffffffff, "WM9705", NULL }, // patch?
{ 0x594d4800, 0xffffffff, "YMF743", NULL },
{ 0x594d4802, 0xffffffff, "YMF752", NULL },
......@@ -291,8 +291,9 @@ void snd_ac97_write_cache(ac97_t *ac97, unsigned short reg, unsigned short value
if (!snd_ac97_valid_reg(ac97, reg))
return;
spin_lock(&ac97->reg_lock);
ac97->write(ac97, reg, ac97->regs[reg] = value);
ac97->regs[reg] = value;
spin_unlock(&ac97->reg_lock);
ac97->write(ac97, reg, value);
set_bit(reg, ac97->reg_accessed);
}
......@@ -301,12 +302,12 @@ static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned
#if 0
if (!snd_ac97_valid_reg(ac97, reg))
return;
spin_lock(&ac97->reg_lock);
//spin_lock(&ac97->reg_lock);
ac97->write(ac97, reg, value);
ac97->regs[reg] = ac97->read(ac97, reg);
if (value != ac97->regs[reg])
snd_printk("AC97 reg=%02x val=%04x real=%04x\n", reg, value, ac97->regs[reg]);
spin_unlock(&ac97->reg_lock);
//spin_unlock(&ac97->reg_lock);
#endif
snd_ac97_write_cache(ac97, reg, value);
}
......@@ -332,27 +333,11 @@ int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
spin_lock(&ac97->reg_lock);
change = ac97->regs[reg] != value;
if (change) {
ac97->write(ac97, reg, value);
ac97->regs[reg] = value;
}
spin_unlock(&ac97->reg_lock);
return change;
}
static int snd_ac97_update_bits_nolock(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value)
{
int change;
unsigned short old, new;
if (!snd_ac97_valid_reg(ac97, reg))
return -EINVAL;
old = ac97->regs[reg];
new = (old & ~mask) | value;
change = old != new;
if (change) {
ac97->write(ac97, reg, new);
ac97->regs[reg] = new;
}
spin_unlock(&ac97->reg_lock);
ac97->write(ac97, reg, value);
} else
spin_unlock(&ac97->reg_lock);
return change;
}
......@@ -372,9 +357,20 @@ static int snd_ac97_update_bits_nolock(ac97_t *ac97, unsigned short reg, unsigne
int snd_ac97_update_bits(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value)
{
int change;
unsigned short old, new;
if (!snd_ac97_valid_reg(ac97, reg))
return -EINVAL;
spin_lock(&ac97->reg_lock);
change = snd_ac97_update_bits_nolock(ac97, reg, mask, value);
spin_unlock(&ac97->reg_lock);
old = ac97->regs[reg];
new = (old & ~mask) | value;
change = old != new;
if (change) {
ac97->regs[reg] = new;
spin_unlock(&ac97->reg_lock);
ac97->write(ac97, reg, new);
} else
spin_unlock(&ac97->reg_lock);
return change;
}
......@@ -389,15 +385,16 @@ static int snd_ac97_ad18xx_update_pcm_bits(ac97_t *ac97, int codec, unsigned sho
new = (old & ~mask) | value;
change = old != new;
if (change) {
ac97->spec.ad18xx.pcmreg[codec] = new;
spin_unlock(&ac97->reg_lock);
/* select single codec */
ac97->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
/* update PCM bits */
ac97->write(ac97, AC97_PCM, new);
/* select all codecs */
ac97->write(ac97, AC97_AD_SERIAL_CFG, 0x7000);
ac97->spec.ad18xx.pcmreg[codec] = new;
}
spin_unlock(&ac97->reg_lock);
} else
spin_unlock(&ac97->reg_lock);
up(&ac97->spec.ad18xx.mutex);
return change;
}
......@@ -795,7 +792,7 @@ static int snd_ac97_spdif_default_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
unsigned int new = 0;
unsigned short val = 0;
int change = 0;
int change;
spin_lock(&ac97->reg_lock);
new = val = ucontrol->value.iec958.status[0] & (IEC958_AES0_PROFESSIONAL|IEC958_AES0_NONAUDIO);
......@@ -826,7 +823,9 @@ static int snd_ac97_spdif_default_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val
}
}
change = ac97->spdif_status != new;
ac97->spdif_status = new;
spin_unlock(&ac97->reg_lock);
if (ac97->flags & AC97_CS_SPDIF) {
int x = (val >> 12) & 0x03;
......@@ -835,21 +834,18 @@ static int snd_ac97_spdif_default_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val
case 2: x = 0; break; // 48.0
default: x = 0; break; // illegal.
}
change = snd_ac97_update_bits_nolock(ac97, AC97_CSR_SPDIF, 0x3fff, ((val & 0xcfff) | (x << 12)));
change |= snd_ac97_update_bits(ac97, AC97_CSR_SPDIF, 0x3fff, ((val & 0xcfff) | (x << 12)));
} else if (ac97->flags & AC97_CX_SPDIF) {
int v;
v = ucontrol->value.iec958.status[0] & (IEC958_AES0_CON_EMPHASIS_5015|IEC958_AES0_CON_NOT_COPYRIGHT) ? 0 : AC97_CXR_COPYRGT;
v |= ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO ? AC97_CXR_SPDIF_AC3 : AC97_CXR_SPDIF_PCM;
change = snd_ac97_update_bits_nolock(ac97, AC97_CXR_AUDIO_MISC,
AC97_CXR_SPDIF_MASK | AC97_CXR_COPYRGT,
v);
v = new & (IEC958_AES0_CON_EMPHASIS_5015|IEC958_AES0_CON_NOT_COPYRIGHT) ? 0 : AC97_CXR_COPYRGT;
v |= new & IEC958_AES0_NONAUDIO ? AC97_CXR_SPDIF_AC3 : AC97_CXR_SPDIF_PCM;
change |= snd_ac97_update_bits(ac97, AC97_CXR_AUDIO_MISC,
AC97_CXR_SPDIF_MASK | AC97_CXR_COPYRGT,
v);
} else {
change = snd_ac97_update_bits_nolock(ac97, AC97_SPDIF, 0x3fff, val);
change |= snd_ac97_update_bits(ac97, AC97_SPDIF, 0x3fff, val);
}
change |= ac97->spdif_status != new;
ac97->spdif_status = new;
spin_unlock(&ac97->reg_lock);
return change;
}
......@@ -1005,11 +1001,11 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
#if 0 /* always set in patch_alc650 */
AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
#endif
AC97_SINGLE("Surround DAC Switch", AC97_ALC650_SURR_DAC_VOL, 15, 1, 1),
AC97_DOUBLE("Surround DAC Volume", AC97_ALC650_SURR_DAC_VOL, 8, 0, 31, 1),
AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1),
AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1),
#endif
};
/* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */
......@@ -1748,7 +1744,7 @@ static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name)
pid->patch(ac97);
return;
}
sprintf(name + strlen(name), " (%x)", id & 0xff);
sprintf(name + strlen(name), " id %x", id & 0xff);
}
......@@ -2224,12 +2220,12 @@ static int set_spdif_rate(ac97_t *ac97, unsigned short rate)
spin_lock(&ac97->reg_lock);
old = ac97->regs[reg] & ~AC97_SC_SPSR_MASK;
spin_unlock(&ac97->reg_lock);
if (old != bits) {
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
snd_ac97_update_bits_nolock(ac97, reg, AC97_SC_SPSR_MASK, bits);
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
snd_ac97_update_bits(ac97, reg, AC97_SC_SPSR_MASK, bits);
}
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF);
spin_unlock(&ac97->reg_lock);
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF);
return 0;
}
......
......@@ -353,8 +353,17 @@ int patch_ad1980(ac97_t * ac97)
int patch_alc650(ac97_t * ac97)
{
unsigned short val;
/* enable spdif in */
snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03);
val = snd_ac97_read(ac97, AC97_ALC650_MULTICH);
val &= ~0xc000; /* slot: 3,4,7,8,6,9 */
snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH,
val | 0x03);
/* full DAC volume */
snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808);
return 0;
}
......@@ -20,9 +20,7 @@
/* Does not work. Warning may block system in capture mode */
/* #define USE_VAR48KRATE */
/* Define this if you want soft ac3 encoding - it's still buggy.. */
/* #define DO_SOFT_AC3 */
/* #define USE_AES_IEC958 */
/* Define this if you want soft ac3 encoding */
#define DO_SOFT_AC3
#define USE_AES_IEC958
......@@ -59,6 +57,9 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */
static long mpu_port[SNDRV_CARDS] = {0x330, [1 ... (SNDRV_CARDS-1)]=-1};
static long fm_port[SNDRV_CARDS] = {0x388, [1 ... (SNDRV_CARDS-1)]=-1};
#ifdef DO_SOFT_AC3
static int soft_ac3[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)]=1};
#endif
MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for C-Media PCI soundcard.");
......@@ -75,6 +76,11 @@ MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{-1},{0x330},{0x320},{0x310
MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
MODULE_PARM_DESC(fm_port, "FM port.");
MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{-1},{0x388},{0x3c8},{0x3e0},{0x3e8}},dialog:list");
#ifdef DO_SOFT_AC3
MODULE_PARM(soft_ac3, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
MODULE_PARM_DESC(soft_ac3, "Sofware-conversion of raw SPDIF packets (model 033 only).");
MODULE_PARM_SYNTAX(soft_ac3, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
#endif
#ifndef PCI_DEVICE_ID_CMEDIA_CM8738
#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111
......@@ -442,6 +448,7 @@ struct snd_stru_cmipci {
unsigned int can_ac3_sw: 1;
unsigned int can_ac3_hw: 1;
unsigned int can_multi_ch: 1;
unsigned int do_soft_ac3: 1;
unsigned int spdif_playback_avail: 1; /* spdif ready? */
unsigned int spdif_playback_enabled: 1; /* spdif switch enabled? */
......@@ -1960,11 +1967,22 @@ static snd_pcm_ops_t snd_cmipci_playback_spdif_ops = {
.prepare = snd_cmipci_playback_spdif_prepare, /* set up rate */
.trigger = snd_cmipci_playback_trigger,
.pointer = snd_cmipci_playback_pointer,
};
#ifdef DO_SOFT_AC3
static snd_pcm_ops_t snd_cmipci_playback_spdif_soft_ops = {
.open = snd_cmipci_playback_spdif_open,
.close = snd_cmipci_playback_spdif_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_cmipci_hw_params,
.hw_free = snd_cmipci_playback_hw_free,
.prepare = snd_cmipci_playback_spdif_prepare, /* set up rate */
.trigger = snd_cmipci_playback_trigger,
.pointer = snd_cmipci_playback_pointer,
.copy = snd_cmipci_ac3_copy,
.silence = snd_cmipci_ac3_silence,
#endif
};
#endif
static snd_pcm_ops_t snd_cmipci_capture_spdif_ops = {
.open = snd_cmipci_capture_spdif_open,
......@@ -2040,7 +2058,14 @@ static int __devinit snd_cmipci_pcm_spdif_new(cmipci_t *cm, int device)
if (err < 0)
return err;
#ifdef DO_SOFT_AC3
if (cm->can_ac3_hw)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_spdif_ops);
else
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_spdif_soft_ops);
#else
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_spdif_ops);
#endif
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cmipci_capture_spdif_ops);
pcm->private_data = cm;
......@@ -2776,7 +2801,10 @@ static void __devinit query_chip(cmipci_t *cm)
if (! detect) {
cm->chip_version = 33;
cm->max_channels = 2;
cm->can_ac3_sw = 1;
if (cm->do_soft_ac3)
cm->can_ac3_sw = 1;
else
cm->can_ac3_hw = 1;
cm->has_dual_dac = 1;
} else {
cm->chip_version = 37;
......@@ -2843,11 +2871,8 @@ static int snd_cmipci_dev_free(snd_device_t *device)
return snd_cmipci_free(cm);
}
static int __devinit snd_cmipci_create(snd_card_t *card,
struct pci_dev *pci,
unsigned long iomidi,
unsigned long iosynth,
cmipci_t **rcmipci)
static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci,
int dev, cmipci_t **rcmipci)
{
cmipci_t *cm;
int err;
......@@ -2855,8 +2880,10 @@ static int __devinit snd_cmipci_create(snd_card_t *card,
.dev_free = snd_cmipci_dev_free,
};
unsigned int val = 0;
unsigned long iomidi = mpu_port[dev];
unsigned long iosynth = fm_port[dev];
int pcm_index, pcm_spdif_index;
*rcmipci = NULL;
if ((err = pci_enable_device(pci)) < 0)
......@@ -2897,6 +2924,9 @@ static int __devinit snd_cmipci_create(snd_card_t *card,
cm->chip_version = 0;
cm->max_channels = 2;
#ifdef DO_SOFT_AC3
cm->do_soft_ac3 = soft_ac3[dev];
#endif
query_chip(cm);
......@@ -3078,10 +3108,7 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci,
break;
}
if ((err = snd_cmipci_create(card, pci,
mpu_port[dev],
fm_port[dev],
&cm)) < 0) {
if ((err = snd_cmipci_create(card, pci, dev, &cm)) < 0) {
snd_card_free(card);
return err;
}
......
......@@ -273,9 +273,6 @@ static void snd_cs46xx_ac97_write(ac97_t *ac97,
unsigned short val)
{
cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return);
#ifndef CONFIG_SND_CS46XX_NEW_DSP
int val2 = 0;
#endif
int codec_index = -1;
/* UGGLY: nr_ac97_codecs == 0 primery codec detection is in progress */
......@@ -287,59 +284,9 @@ static void snd_cs46xx_ac97_write(ac97_t *ac97,
else
snd_assert(0,return);
#ifndef CONFIG_SND_CS46XX_NEW_DSP
if (reg == AC97_CD)
val2 = snd_cs46xx_codec_read(chip, AC97_CD, codec_index);
#endif
chip->active_ctrl(chip, 1);
snd_cs46xx_codec_write(chip, reg, val, codec_index);
#ifndef CONFIG_SND_CS46XX_NEW_DSP
/* Benny: I've not found *one* soundcard where
this code below could do any sense, and
with the HW mixering it's anyway broken, with
more then 1 PCM stream the amplifier will not
be turned off by unmuting CD channel. So just
lets skip it.
*/
/*
* Adjust power if the mixer is selected/deselected according
* to the CD.
*
* IF the CD is a valid input source (mixer or direct) AND
* the CD is not muted THEN power is needed
*
* We do two things. When record select changes the input to
* add/remove the CD we adjust the power count if the CD is
* unmuted.
*
* When the CD mute changes we adjust the power level if the
* CD was a valid input.
*
* We also check for CD volume != 0, as the CD mute isn't
* normally tweaked from userspace.
*/
/* CD mute change ? */
/* Benny: this hack dont seems to make any sense to me, at least on the Game Theater XP,
Turning of the amplifier just make the PCM sound very distorcionated.
is this really needed ????????????????
*/
if (reg == AC97_CD) {
/* Mute bit change ? */
if ((val2^val)&0x8000 || ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val)) {
/* Mute on */
if(val&0x8000 || val == 0x1f1f)
chip->amplifier_ctrl(chip, -1);
else /* Mute off power on */
chip->amplifier_ctrl(chip, 1);
}
}
chip->active_ctrl(chip, -1);
#endif
}
......@@ -1506,7 +1453,6 @@ static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pc
if (chip->accept_valid)
substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
chip->active_ctrl(chip, 1);
chip->amplifier_ctrl(chip, 1);
return 0;
}
......@@ -1570,7 +1516,6 @@ static int snd_cs46xx_capture_open(snd_pcm_substream_t * substream)
substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
chip->active_ctrl(chip, 1);
chip->amplifier_ctrl(chip, 1);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
snd_pcm_hw_constraint_list(substream->runtime, 0,
......@@ -1605,7 +1550,6 @@ static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream)
cpcm->substream = NULL;
snd_free_pci_pages(chip->pci, cpcm->hw_size, cpcm->hw_area, cpcm->hw_addr);
chip->active_ctrl(chip, -1);
chip->amplifier_ctrl(chip, -1);
return 0;
}
......@@ -1617,7 +1561,6 @@ static int snd_cs46xx_capture_close(snd_pcm_substream_t * substream)
chip->capt.substream = NULL;
snd_free_pci_pages(chip->pci, chip->capt.hw_size, chip->capt.hw_area, chip->capt.hw_addr);
chip->active_ctrl(chip, -1);
chip->amplifier_ctrl(chip, -1);
return 0;
}
......@@ -3545,9 +3488,6 @@ static void voyetra_mixer_init (cs46xx_t *chip)
{
snd_printdd ("initializing Voyetra mixer\n");
/* turnon Amplifier and leave it on */
chip->amplifier_ctrl(chip, 1);
/* Enable SPDIF out */
snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE0);
snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, EGPIODR_GPOE0);
......@@ -3566,9 +3506,6 @@ static void hercules_mixer_init (cs46xx_t *chip)
snd_printdd ("initializing Hercules mixer\n");
#ifdef CONFIG_SND_CS46XX_NEW_DSP
/* turnon Amplifier and leave it on */
chip->amplifier_ctrl(chip, 1);
for (idx = 0 ; idx < sizeof(snd_hercules_controls) /
sizeof(snd_hercules_controls[0]) ; idx++) {
snd_kcontrol_t *kctl;
......@@ -3708,6 +3645,8 @@ static struct cs_card_type __devinitdata cards[] = {
#ifdef CONFIG_PM
void snd_cs46xx_suspend(cs46xx_t *chip)
{
int amp_saved;
snd_card_t *card = chip->card;
if (card->power_state == SNDRV_CTL_POWER_D3hot)
......@@ -3715,7 +3654,13 @@ void snd_cs46xx_suspend(cs46xx_t *chip)
snd_pcm_suspend_all(chip->pcm);
// chip->ac97_powerdown = snd_cs46xx_codec_read(chip, AC97_POWER_CONTROL);
// chip->ac97_general_purpose = snd_cs46xx_codec_read(chip, BA0_AC97_GENERAL_PURPOSE);
amp_saved = chip->amplifier;
/* turn off amp */
chip->amplifier_ctrl(chip, -chip->amplifier);
snd_cs46xx_hw_stop(chip);
/* disable CLKRUN */
chip->active_ctrl(chip, -chip->amplifier);
chip->amplifier = amp_saved; /* restore the status */
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
}
......@@ -3748,11 +3693,10 @@ void snd_cs46xx_resume(cs46xx_t *chip)
snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
if (amp_saved)
chip->amplifier_ctrl(chip, 1); /* try to turn on */
if (! amp_saved) {
chip->amplifier = 1;
chip->active_ctrl(chip, -1);
}
chip->amplifier_ctrl(chip, 1); /* turn amp on */
else
chip->active_ctrl(chip, -1); /* disable CLKRUN */
chip->amplifier = amp_saved;
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
}
......@@ -3853,11 +3797,11 @@ int __devinit snd_cs46xx_create(snd_card_t * card,
for (cp = &cards[0]; cp->name; cp++) {
if (cp->vendor == ss_vendor && cp->id == ss_card) {
snd_printd ("hack for %s enabled\n", cp->name);
if (cp->init)
cp->init(chip);
chip->amplifier_ctrl = cp->amp;
chip->active_ctrl = cp->active;
chip->mixer_init = cp->mixer_init;
if (cp->init)
cp->init(chip);
break;
}
}
......@@ -3878,7 +3822,7 @@ int __devinit snd_cs46xx_create(snd_card_t * card,
if (chip->active_ctrl == NULL)
chip->active_ctrl = amp_none;
chip->active_ctrl(chip, 1);
chip->active_ctrl(chip, 1); /* enable CLKRUN */
pci_set_master(pci);
......@@ -3929,7 +3873,10 @@ int __devinit snd_cs46xx_create(snd_card_t * card,
return err;
}
chip->active_ctrl(chip, -1);
/* turn on amplifier */
chip->amplifier_ctrl(chip, 1);
chip->active_ctrl(chip, -1); /* disable CLKRUN */
*rchip = chip;
return 0;
......
......@@ -182,7 +182,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
strcpy(card->driver, "EMU10K1");
strcpy(card->shortname, "Sound Blaster Live!");
}
sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, emu->port, emu->irq);
sprintf(card->longname, "%s (rev.%d) at 0x%lx, irq %i", card->shortname, emu->revision, emu->port, emu->irq);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
......
......@@ -161,6 +161,26 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir)
SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
SPCS_GENERATIONSTATUS | 0x00001200 |
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
if (emu->audigy && emu->revision == 4) { /* audigy2 */
/* Hacks for Alice3 to work independent of haP16V driver */
u32 tmp;
//Setup SRCMulti_I2S SamplingRate
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
tmp &= 0xfffff1ff;
tmp |= (0x2<<9);
snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
outl(0x600000, emu->port + 0x20);
outl(0x14, emu->port + 0x24);
/* Setup SRCMulti Input Audio Enable */
outl(0x6E0000, emu->port + 0x20);
outl(0xFF00FF00, emu->port + 0x24);
}
/*
* Clear page with silence & setup all pointers to this page
*/
......@@ -185,9 +205,15 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir)
* Lock Sound Memory = 0
* Auto Mute = 1
*/
if (emu->audigy)
outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
else if (emu->model == 0x20 ||
if (emu->audigy) {
if (emu->revision == 4) /* audigy2 */
outl(HCFG_AUDIOENABLE |
HCFG_AC3ENABLE_CDSPDIF |
HCFG_AC3ENABLE_GPSPDIF |
HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
else
outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
} else if (emu->model == 0x20 ||
emu->model == 0xc400 ||
(emu->model == 0x21 && emu->revision < 6))
outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG);
......@@ -221,9 +247,17 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir)
outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
/* Enable analog/digital outs on audigy */
if (emu->audigy)
if (emu->audigy) {
outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
if (emu->revision == 4) { /* audigy2 */
/* Unmute Analog now. Set GPO6 to 1 for Apollo.
* This has to be done after init ALice3 I2SOut beyond 48KHz.
* So, sequence is important. */
outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG);
}
}
#if 0
{
unsigned int tmp;
......
......@@ -359,7 +359,7 @@ static int snd_emu10k1_playback_hw_params(snd_pcm_substream_t * substream,
if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
return err;
if ((err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params))) < 0)
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err;
if (err > 0) { /* change */
snd_util_memblk_t *memblk;
......@@ -401,7 +401,7 @@ static int snd_emu10k1_playback_hw_free(snd_pcm_substream_t * substream)
epcm->memblk = NULL;
epcm->start_addr = 0;
}
snd_pcm_sgbuf_free(substream);
snd_pcm_lib_free_pages(substream);
return 0;
}
......@@ -784,10 +784,6 @@ static int snd_emu10k1_playback_open(snd_pcm_substream_t * substream)
runtime->private_data = epcm;
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_playback;
if ((err = snd_pcm_sgbuf_init(substream, emu->pci, 32)) < 0) {
snd_magic_kfree(epcm);
return err;
}
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {
snd_magic_kfree(epcm);
return err;
......@@ -814,7 +810,6 @@ static int snd_emu10k1_playback_close(snd_pcm_substream_t * substream)
emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number];
mix->epcm = NULL;
snd_pcm_sgbuf_delete(substream);
snd_emu10k1_pcm_mixer_notify(emu->card, mix, 0);
return 0;
}
......@@ -953,8 +948,6 @@ static snd_pcm_ops_t snd_emu10k1_playback_ops = {
.prepare = snd_emu10k1_playback_prepare,
.trigger = snd_emu10k1_playback_trigger,
.pointer = snd_emu10k1_playback_pointer,
.copy = snd_pcm_sgbuf_ops_copy_playback,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -999,9 +992,12 @@ int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
strcpy(pcm->name, "EMU10K1");
emu->pcm = pcm;
for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
if ((err = snd_pcm_lib_preallocate_sg_pages(emu->pci, substream)) < 0)
return err;
for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
snd_pcm_lib_preallocate_pci_pages(emu->pci, substream, 64*1024, 64*1024);
return err;
if (rpcm)
*rpcm = pcm;
......
......@@ -150,6 +150,9 @@ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
#define ES_REG_STATUS 0x04 /* R/O: Interrupt/Chip select status register */
#define ES_INTR (1<<31) /* Interrupt is pending */
#define ES_1371_ST_AC97_RST (1<<29) /* CT5880 AC'97 Reset bit */
#define ES_1373_REAR_BIT27 (1<<27) /* rear bits: 000 - front, 010 - mirror, 101 - separate */
#define ES_1373_REAR_BIT26 (1<<26)
#define ES_1373_REAR_BIT24 (1<<24)
#define ES_1373_GPIO_INT_EN(o)(((o)&0x0f)<<20)/* GPIO [3:0] pins - interrupt enable */
#define ES_1373_SPDIF_EN (1<<18) /* SPDIF enable */
#define ES_1373_SPDIF_TEST (1<<17) /* SPDIF test */
......@@ -1197,7 +1200,11 @@ static int __devinit snd_ensoniq_pcm(ensoniq_t * ensoniq, int device, snd_pcm_t
if (err < 0)
return err;
#ifdef CHIP1370
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ensoniq_playback2_ops);
#else
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ensoniq_playback1_ops);
#endif
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ensoniq_capture_ops);
pcm->private_data = ensoniq;
......@@ -1239,8 +1246,11 @@ static int __devinit snd_ensoniq_pcm2(ensoniq_t * ensoniq, int device, snd_pcm_t
if (err < 0)
return err;
#ifdef CHIP1370
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ensoniq_playback1_ops);
#else
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ensoniq_playback2_ops);
#endif
pcm->private_data = ensoniq;
pcm->private_free = snd_ensoniq_pcm_free2;
pcm->info_flags = 0;
......@@ -1422,6 +1432,53 @@ static int snd_es1371_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
static snd_kcontrol_new_t snd_es1371_mixer_spdif __devinitdata =
ES1371_SPDIF("IEC958 Playback Switch");
static int snd_es1373_rear_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int snd_es1373_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
int val = 0;
spin_lock_irq(&ensoniq->reg_lock);
if ((ensoniq->cssr & (ES_1373_REAR_BIT27|ES_1373_REAR_BIT26|ES_1373_REAR_BIT24)) == ES_1373_REAR_BIT26)
val = 1;
ucontrol->value.integer.value[0] = val;
spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
static int snd_es1373_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
unsigned int nval1;
int change;
nval1 = ucontrol->value.integer.value[0] ? ES_1373_REAR_BIT26 : (ES_1373_REAR_BIT27|ES_1373_REAR_BIT24);
spin_lock_irq(&ensoniq->reg_lock);
change = (ensoniq->cssr & (ES_1373_REAR_BIT27|ES_1373_REAR_BIT26|ES_1373_REAR_BIT24)) != nval1;
ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT26|ES_1373_REAR_BIT24);
ensoniq->cssr |= nval1;
outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
spin_unlock_irq(&ensoniq->reg_lock);
return change;
}
static snd_kcontrol_new_t snd_ens1373_rear __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "AC97 2ch->4ch Copy Switch",
.info = snd_es1373_rear_info,
.get = snd_es1373_rear_get,
.put = snd_es1373_rear_put,
};
static void snd_ensoniq_mixer_free_ac97(ac97_t *ac97)
{
ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, ac97->private_data, return);
......@@ -1432,7 +1489,7 @@ static struct {
unsigned short vid; /* vendor ID */
unsigned short did; /* device ID */
unsigned char rev; /* revision */
} __devinitdata es1371_spdif_present[] = {
} es1371_spdif_present[] __devinitdata = {
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
......@@ -1484,6 +1541,12 @@ static int snd_ensoniq_1371_mixer(ensoniq_t * ensoniq)
snd_ctl_add(card, kctl);
break;
}
if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) {
/* mirror rear to front speakers */
ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24);
ensoniq->cssr |= ES_1373_REAR_BIT26;
snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_rear, ensoniq));
}
return 0;
}
......
......@@ -42,6 +42,12 @@ static int __devinit snd_vt1724_amp_init(ice1712_t *ice)
return 0;
}
static int __devinit snd_vt1724_amp_add_controls(ice1712_t *ice)
{
/* we use pins 39 and 41 of the VT1616 for left and right read outputs */
snd_ac97_write_cache(ice->ac97, 0x5a, snd_ac97_read(ice->ac97, 0x5a) & ~0x8000);
}
/* entry point */
struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
......@@ -49,6 +55,7 @@ struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
VT1724_SUBDEVICE_AUDIO2000,
"AMP Ltd AUDIO2000",
snd_vt1724_amp_init,
snd_vt1724_amp_add_controls,
},
{ } /* terminator */
};
......
......@@ -70,7 +70,6 @@
#include <sound/asoundef.h>
#define SNDRV_GET_ID
#include <sound/initval.h>
#include <sound/info.h>
#include <asm/io.h>
......@@ -272,6 +271,19 @@ static inline unsigned int snd_rme32_capture_ptr(rme32_t * rme32)
& RME32_RCR_AUDIO_ADDR_MASK) >> rme32->capture_frlog;
}
static int snd_rme32_ratecode(int rate)
{
switch (rate) {
case 32000: return SNDRV_PCM_RATE_32000;
case 44100: return SNDRV_PCM_RATE_44100;
case 48000: return SNDRV_PCM_RATE_48000;
case 64000: return SNDRV_PCM_RATE_64000;
case 88200: return SNDRV_PCM_RATE_88200;
case 96000: return SNDRV_PCM_RATE_96000;
}
return 0;
}
static int snd_rme32_playback_silence(snd_pcm_substream_t * substream, int channel, /* not used (interleaved data) */
snd_pcm_uframes_t pos,
snd_pcm_uframes_t count)
......@@ -663,14 +675,21 @@ static int
snd_rme32_playback_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * params)
{
int err, rate, dummy;
rme32_t *rme32 = _snd_pcm_substream_chip(substream);
int err;
if ((err = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(params))) < 0)
return err;
spin_lock_irq(&rme32->lock);
if ((err = snd_rme32_playback_setrate(rme32, params_rate(params))) < 0) {
if ((rme32->rcreg & RME32_RCR_KMODE) &&
(rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) {
/* AutoSync */
if (params_rate(params) != rate) {
spin_unlock_irq(&rme32->lock);
return -EIO;
}
} else if ((err = snd_rme32_playback_setrate(rme32, params_rate(params))) < 0) {
spin_unlock_irq(&rme32->lock);
return err;
}
......@@ -710,8 +729,9 @@ snd_rme32_capture_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * params)
{
unsigned long flags;
int err, isadat, rate;
rme32_t *rme32 = _snd_pcm_substream_chip(substream);
int err, isadat;
snd_pcm_runtime_t *runtime = substream->runtime;
if ((err = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(params))) < 0)
......@@ -729,9 +749,16 @@ snd_rme32_capture_hw_params(snd_pcm_substream_t * substream,
spin_unlock_irqrestore(&rme32->lock, flags);
return err;
}
if (params_rate(params) != snd_rme32_capture_getrate(rme32, &isadat)) {
spin_unlock_irqrestore(&rme32->lock, flags);
return -EBUSY;
if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) {
if (params_rate(params) != rate) {
spin_unlock_irqrestore(&rme32->lock, flags);
return -EIO;
}
if ((isadat && runtime->hw.channels_min == 2) ||
(!isadat && runtime->hw.channels_min == 8)) {
spin_unlock_irqrestore(&rme32->lock, flags);
return -EIO;
}
}
/* AutoSync off for recording */
rme32->wcreg &= ~RME32_WCR_AUTOSYNC;
......@@ -791,7 +818,8 @@ static void snd_rme32_playback_stop(rme32_t * rme32)
writel(0, rme32->iobase + RME32_IO_CONFIRM_ACTION_IRQ);
}
rme32->wcreg &= ~RME32_WCR_START;
rme32->wcreg |= RME32_WCR_MUTE;
if (rme32->wcreg & RME32_WCR_SEL)
rme32->wcreg |= RME32_WCR_MUTE;
writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
}
......@@ -838,12 +866,17 @@ static snd_pcm_hw_constraint_list_t hw_constraints_period_bytes = {
static int snd_rme32_playback_spdif_open(snd_pcm_substream_t * substream)
{
unsigned long flags;
int rate, dummy;
rme32_t *rme32 = _snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_set_sync(substream);
spin_lock_irqsave(&rme32->lock, flags);
if (rme32->playback_substream != NULL) {
spin_unlock_irqrestore(&rme32->lock, flags);
return -EBUSY;
}
rme32->wcreg &= ~RME32_WCR_ADAT;
writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
rme32->playback_substream = substream;
......@@ -856,7 +889,13 @@ static int snd_rme32_playback_spdif_open(snd_pcm_substream_t * substream)
runtime->hw.rates |= SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000;
runtime->hw.rate_max = 96000;
}
if ((rme32->rcreg & RME32_RCR_KMODE) &&
(rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) {
/* AutoSync */
runtime->hw.rates = snd_rme32_ratecode(rate);
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
RME32_BUFFER_SIZE, RME32_BUFFER_SIZE);
......@@ -874,23 +913,17 @@ static int snd_rme32_playback_spdif_open(snd_pcm_substream_t * substream)
static int snd_rme32_capture_spdif_open(snd_pcm_substream_t * substream)
{
unsigned long flags;
int isadat;
int isadat, rate;
rme32_t *rme32 = _snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER);
if (snd_rme32_capture_getrate(rme32, &isadat) < 0) {
/* no input */
return -EIO;
}
if (isadat) {
/* ADAT input */
return -EBUSY;
}
snd_pcm_set_sync(substream);
spin_lock_irqsave(&rme32->lock, flags);
if (rme32->capture_substream != NULL) {
spin_unlock_irqrestore(&rme32->lock, flags);
return -EBUSY;
}
rme32->capture_substream = substream;
rme32->capture_ptr = 0;
spin_unlock_irqrestore(&rme32->lock, flags);
......@@ -900,6 +933,14 @@ static int snd_rme32_capture_spdif_open(snd_pcm_substream_t * substream)
runtime->hw.rates |= SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000;
runtime->hw.rate_max = 96000;
}
if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) {
if (isadat) {
return -EIO;
}
runtime->hw.rates = snd_rme32_ratecode(rate);
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
......@@ -915,12 +956,17 @@ static int
snd_rme32_playback_adat_open(snd_pcm_substream_t *substream)
{
unsigned long flags;
int rate, dummy;
rme32_t *rme32 = _snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_set_sync(substream);
spin_lock_irqsave(&rme32->lock, flags);
if (rme32->playback_substream != NULL) {
spin_unlock_irqrestore(&rme32->lock, flags);
return -EBUSY;
}
rme32->wcreg |= RME32_WCR_ADAT;
writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
rme32->playback_substream = substream;
......@@ -929,6 +975,13 @@ snd_rme32_playback_adat_open(snd_pcm_substream_t *substream)
spin_unlock_irqrestore(&rme32->lock, flags);
runtime->hw = snd_rme32_playback_adat_info;
if ((rme32->rcreg & RME32_RCR_KMODE) &&
(rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) {
/* AutoSync */
runtime->hw.rates = snd_rme32_ratecode(rate);
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
RME32_BUFFER_SIZE, RME32_BUFFER_SIZE);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
......@@ -940,27 +993,31 @@ static int
snd_rme32_capture_adat_open(snd_pcm_substream_t *substream)
{
unsigned long flags;
int isadat;
int isadat, rate;
rme32_t *rme32 = _snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER);
if (snd_rme32_capture_getrate(rme32, &isadat) < 0) {
/* no input */
return -EIO;
}
if (!isadat) {
/* S/PDIF input */
return -EBUSY;
}
snd_pcm_set_sync(substream);
runtime->hw = snd_rme32_capture_adat_info;
if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) {
if (!isadat) {
return -EIO;
}
runtime->hw.rates = snd_rme32_ratecode(rate);
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
snd_pcm_set_sync(substream);
spin_lock_irqsave(&rme32->lock, flags);
if (rme32->capture_substream != NULL) {
spin_unlock_irqrestore(&rme32->lock, flags);
return -EBUSY;
}
rme32->capture_substream = substream;
rme32->capture_ptr = 0;
spin_unlock_irqrestore(&rme32->lock, flags);
runtime->hw = snd_rme32_capture_adat_info;
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
RME32_BUFFER_SIZE, RME32_BUFFER_SIZE);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
......@@ -1010,7 +1067,8 @@ static int snd_rme32_playback_prepare(snd_pcm_substream_t * substream)
snd_rme32_playback_stop(rme32);
}
writel(0, rme32->iobase + RME32_IO_RESET_POS);
rme32->wcreg &= ~RME32_WCR_MUTE;
if (rme32->wcreg & RME32_WCR_SEL)
rme32->wcreg &= ~RME32_WCR_MUTE;
writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
spin_unlock_irqrestore(&rme32->lock, flags);
return 0;
......@@ -1464,7 +1522,7 @@ snd_rme32_proc_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer)
snd_iprintf(buffer, " sample rate: %d Hz\n",
snd_rme32_playback_getrate(rme32));
}
if (rme32->wcreg & RME32_RCR_KMODE) {
if (rme32->rcreg & RME32_RCR_KMODE) {
snd_iprintf(buffer, " sample clock source: AutoSync\n");
} else {
snd_iprintf(buffer, " sample clock source: Internal\n");
......@@ -1529,6 +1587,10 @@ snd_rme32_put_loopback_control(snd_kcontrol_t * kcontrol,
spin_lock_irqsave(&rme32->lock, flags);
val = (rme32->wcreg & ~RME32_WCR_SEL) | val;
change = val != rme32->wcreg;
if (ucontrol->value.integer.value[0])
val &= ~RME32_WCR_MUTE;
else
val |= RME32_WCR_MUTE;
writel(rme32->wcreg =
val, rme32->iobase + RME32_IO_CONTROL_REGISTER);
spin_unlock_irqrestore(&rme32->lock, flags);
......
......@@ -23,6 +23,7 @@
#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/pci.h>
......@@ -817,10 +818,18 @@ static inline int snd_hdsp_midi_input_available (hdsp_t *hdsp, int id)
static inline int snd_hdsp_midi_output_possible (hdsp_t *hdsp, int id)
{
int fifo_bytes_used;
if (id) {
return (hdsp_read(hdsp, HDSP_midiStatusOut1) & 0xff) < 128;
fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut1) & 0xff;
} else {
return (hdsp_read(hdsp, HDSP_midiStatusOut0) & 0xff)< 128;
fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut0) & 0xff;
}
if (fifo_bytes_used < 128) {
return 128 - fifo_bytes_used;
} else {
return 0;
}
}
......
......@@ -757,9 +757,9 @@ int snd_trident_allocate_pcm_mem(snd_pcm_substream_t * substream,
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
int err;
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err;
if (trident->tlb.entries) {
if ((err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params))) < 0)
return err;
if (err > 0) { /* change */
if (voice->memblk)
snd_trident_free_pages(trident, voice->memblk);
......@@ -767,9 +767,6 @@ int snd_trident_allocate_pcm_mem(snd_pcm_substream_t * substream,
if (voice->memblk == NULL)
return -ENOMEM;
}
} else {
if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
return err;
}
return 0;
}
......@@ -860,9 +857,8 @@ static int snd_trident_hw_free(snd_pcm_substream_t * substream)
snd_trident_free_pages(trident, voice->memblk);
voice->memblk = NULL;
}
snd_pcm_sgbuf_free(substream);
} else
snd_pcm_lib_free_pages(substream);
}
snd_pcm_lib_free_pages(substream);
if (evoice != NULL) {
snd_trident_free_voice(trident, evoice);
voice->extra = NULL;
......@@ -1765,19 +1761,6 @@ static snd_pcm_hardware_t snd_trident_spdif_7018 =
.fifo_size = 0,
};
static int snd_trident_sgbuf_init(trident_t *trident, snd_pcm_substream_t *substream)
{
if (trident->tlb.entries)
return snd_pcm_sgbuf_init(substream, trident->pci, 32);
return 0;
}
static void snd_trident_sgbuf_delete(trident_t *trident, snd_pcm_substream_t *substream)
{
if (trident->tlb.entries)
snd_pcm_sgbuf_delete(substream);
}
static void snd_trident_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
......@@ -1794,15 +1777,10 @@ static int snd_trident_playback_open(snd_pcm_substream_t * substream)
trident_t *trident = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_trident_voice_t *voice;
int err;
if ((err = snd_trident_sgbuf_init(trident, substream)) < 0)
return err;
voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);
if (voice == NULL) {
snd_trident_sgbuf_delete(trident, substream);
if (voice == NULL)
return -EAGAIN;
}
snd_trident_pcm_mixer_build(trident, voice, substream);
voice->substream = substream;
runtime->private_data = voice;
......@@ -1829,7 +1807,6 @@ static int snd_trident_playback_close(snd_pcm_substream_t * substream)
snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data;
snd_trident_pcm_mixer_free(trident, voice, substream);
snd_trident_sgbuf_delete(trident, substream);
return 0;
}
......@@ -1849,15 +1826,10 @@ static int snd_trident_spdif_open(snd_pcm_substream_t * substream)
trident_t *trident = snd_pcm_substream_chip(substream);
snd_trident_voice_t *voice;
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
if ((err = snd_trident_sgbuf_init(trident, substream)) < 0)
return err;
voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);
if (voice == NULL) {
snd_trident_sgbuf_delete(trident, substream);
if (voice == NULL)
return -EAGAIN;
}
voice->spdif = 1;
voice->substream = substream;
trident->spdif_pcm_bits = trident->spdif_bits;
......@@ -1913,7 +1885,6 @@ static int snd_trident_spdif_close(snd_pcm_substream_t * substream)
trident->spdif_pcm_ctl->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO, &trident->spdif_pcm_ctl->id);
snd_trident_sgbuf_delete(trident, substream);
return 0;
}
......@@ -1933,15 +1904,10 @@ static int snd_trident_capture_open(snd_pcm_substream_t * substream)
trident_t *trident = snd_pcm_substream_chip(substream);
snd_trident_voice_t *voice;
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
if ((err = snd_trident_sgbuf_init(trident, substream)) < 0)
return err;
voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);
if (voice == NULL) {
snd_trident_sgbuf_delete(trident, substream);
if (voice == NULL)
return -EAGAIN;
}
voice->capture = 1;
voice->substream = substream;
runtime->private_data = voice;
......@@ -1963,8 +1929,6 @@ static int snd_trident_capture_open(snd_pcm_substream_t * substream)
---------------------------------------------------------------------------*/
static int snd_trident_capture_close(snd_pcm_substream_t * substream)
{
trident_t *trident = snd_pcm_substream_chip(substream);
snd_trident_sgbuf_delete(trident, substream);
return 0;
}
......@@ -1982,17 +1946,12 @@ static int snd_trident_capture_close(snd_pcm_substream_t * substream)
static int snd_trident_foldback_open(snd_pcm_substream_t * substream)
{
trident_t *trident = snd_pcm_substream_chip(substream);
int err;
snd_trident_voice_t *voice;
snd_pcm_runtime_t *runtime = substream->runtime;
if ((err = snd_trident_sgbuf_init(trident, substream)) < 0)
return err;
voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);
if (voice == NULL) {
snd_trident_sgbuf_delete(trident, substream);
if (voice == NULL)
return -EAGAIN;
}
voice->foldback_chan = substream->number;
voice->substream = substream;
runtime->private_data = voice;
......@@ -2022,7 +1981,6 @@ static int snd_trident_foldback_close(snd_pcm_substream_t * substream)
spin_lock_irq(&trident->reg_lock);
outb(0x00, TRID_REG(trident, T4D_RCI + voice->foldback_chan));
spin_unlock_irq(&trident->reg_lock);
snd_trident_sgbuf_delete(trident, substream);
return 0;
}
......@@ -2050,8 +2008,6 @@ static snd_pcm_ops_t snd_trident_nx_playback_ops = {
.prepare = snd_trident_playback_prepare,
.trigger = snd_trident_trigger,
.pointer = snd_trident_playback_pointer,
.copy = snd_pcm_sgbuf_ops_copy_playback,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -2075,8 +2031,6 @@ static snd_pcm_ops_t snd_trident_nx_capture_ops = {
.prepare = snd_trident_capture_prepare,
.trigger = snd_trident_trigger,
.pointer = snd_trident_capture_pointer,
.copy = snd_pcm_sgbuf_ops_copy_capture,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -2111,8 +2065,6 @@ static snd_pcm_ops_t snd_trident_nx_foldback_ops = {
.prepare = snd_trident_foldback_prepare,
.trigger = snd_trident_trigger,
.pointer = snd_trident_playback_pointer,
.copy = snd_pcm_sgbuf_ops_copy_capture,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -2136,8 +2088,6 @@ static snd_pcm_ops_t snd_trident_nx_spdif_ops = {
.prepare = snd_trident_spdif_prepare,
.trigger = snd_trident_trigger,
.pointer = snd_trident_spdif_pointer,
.copy = snd_pcm_sgbuf_ops_copy_playback,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -2166,24 +2116,21 @@ static void snd_trident_pcm_free(snd_pcm_t *pcm)
{
trident_t *trident = snd_magic_cast(trident_t, pcm->private_data, return);
trident->pcm = NULL;
if (! trident->tlb.entries)
snd_pcm_lib_preallocate_free_for_all(pcm);
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static void snd_trident_foldback_pcm_free(snd_pcm_t *pcm)
{
trident_t *trident = snd_magic_cast(trident_t, pcm->private_data, return);
trident->foldback = NULL;
if (! trident->tlb.entries)
snd_pcm_lib_preallocate_free_for_all(pcm);
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static void snd_trident_spdif_pcm_free(snd_pcm_t *pcm)
{
trident_t *trident = snd_magic_cast(trident_t, pcm->private_data, return);
trident->spdif = NULL;
if (! trident->tlb.entries)
snd_pcm_lib_preallocate_free_for_all(pcm);
snd_pcm_lib_preallocate_free_for_all(pcm);
}
/*---------------------------------------------------------------------------
......@@ -2226,7 +2173,9 @@ int __devinit snd_trident_pcm(trident_t * trident, int device, snd_pcm_t ** rpcm
strcpy(pcm->name, "Trident 4DWave");
trident->pcm = pcm;
if (! trident->tlb.entries)
if (trident->tlb.entries)
snd_pcm_lib_preallocate_sg_pages_for_all(trident->pci, pcm);
else
snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, pcm, 64*1024, 128*1024);
if (rpcm)
......@@ -2279,7 +2228,9 @@ int __devinit snd_trident_foldback_pcm(trident_t * trident, int device, snd_pcm_
}
trident->foldback = foldback;
if (! trident->tlb.entries)
if (trident->tlb.entries)
snd_pcm_lib_preallocate_sg_pages_for_all(trident->pci, foldback);
else
snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, foldback, 64*1024, 128*1024);
if (rpcm)
......@@ -2321,7 +2272,9 @@ int __devinit snd_trident_spdif_pcm(trident_t * trident, int device, snd_pcm_t *
strcpy(spdif->name, "Trident 4DWave IEC958");
trident->spdif = spdif;
if (! trident->tlb.entries)
if (trident->tlb.entries)
snd_pcm_lib_preallocate_sg_pages_for_all(trident->pci, spdif);
else
snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, spdif, 64*1024, 128*1024);
if (rpcm)
......
......@@ -668,7 +668,7 @@ static int snd_via82xx_hw_params(snd_pcm_substream_t * substream,
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
int err;
err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0)
return err;
err = build_via_table(viadev, substream, chip->pci,
......@@ -690,7 +690,7 @@ static int snd_via82xx_hw_free(snd_pcm_substream_t * substream)
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
clean_via_table(viadev, substream, chip->pci);
snd_pcm_sgbuf_free(substream);
snd_pcm_lib_free_pages(substream);
return 0;
}
......@@ -740,16 +740,20 @@ static int snd_via686_capture_prepare(snd_pcm_substream_t *substream)
*/
static int via_lock_rate(struct via_rate_lock *rec, int rate)
{
int changed = 0;
spin_lock(&rec->lock);
if (rec->rate) {
if (rec->rate != rate && rec->used > 1) {
spin_unlock(&rec->lock);
return -EINVAL;
}
} else
} else {
rec->rate = rate;
changed = 1;
}
spin_unlock(&rec->lock);
return 0;
return changed;
}
/*
......@@ -761,19 +765,24 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream)
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
unsigned long port = chip->port + viadev->reg_offset;
snd_pcm_runtime_t *runtime = substream->runtime;
int rate_changed;
u32 rbits;
if (via_lock_rate(&chip->rates[0], runtime->rate) < 0)
return -EINVAL;
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
if (viadev->reg_offset == 0x30) /* DSX3 */
if ((rate_changed = via_lock_rate(&chip->rates[0], runtime->rate)) < 0)
return rate_changed;
if (rate_changed) {
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
}
rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000;
snd_assert((rbits & ~0xfffff) == 0, return -EINVAL);
snd_via82xx_channel_reset(chip, viadev);
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
outb(0 , VIAREG(chip, PLAYBACK_VOLUME_L));
outb(0 , VIAREG(chip, PLAYBACK_VOLUME_R));
outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) | /* format */
(runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) | /* stereo */
(0xffff * runtime->rate)/(48000/16) | /* rate */
rbits | /* rate */
0xff000000, /* STOP index is never reached */
port + VIA_REG_OFFSET_STOP_IDX);
return 0;
......@@ -796,6 +805,7 @@ static int snd_via8233_multi_prepare(snd_pcm_substream_t *substream)
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_PCM_SURR_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_via82xx_channel_reset(chip, viadev);
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
......@@ -894,8 +904,6 @@ static int snd_via82xx_pcm_open(via82xx_t *chip, viadev_t *viadev, snd_pcm_subst
}
spin_unlock_irqrestore(&ratep->lock, flags);
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
/* we may remove following constaint when we modify table entries
in interrupt */
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
......@@ -977,7 +985,6 @@ static int snd_via82xx_pcm_close(snd_pcm_substream_t * substream)
spin_unlock_irqrestore(&ratep->lock, flags);
viadev->substream = NULL;
snd_pcm_sgbuf_delete(substream);
return 0;
}
......@@ -992,8 +999,6 @@ static snd_pcm_ops_t snd_via686_playback_ops = {
.prepare = snd_via686_playback_prepare,
.trigger = snd_via82xx_pcm_trigger,
.pointer = snd_via686_pcm_pointer,
.copy = snd_pcm_sgbuf_ops_copy_playback,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -1007,8 +1012,6 @@ static snd_pcm_ops_t snd_via686_capture_ops = {
.prepare = snd_via686_capture_prepare,
.trigger = snd_via82xx_pcm_trigger,
.pointer = snd_via686_pcm_pointer,
.copy = snd_pcm_sgbuf_ops_copy_capture,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -1022,8 +1025,6 @@ static snd_pcm_ops_t snd_via8233_playback_ops = {
.prepare = snd_via8233_playback_prepare,
.trigger = snd_via82xx_pcm_trigger,
.pointer = snd_via8233_pcm_pointer,
.copy = snd_pcm_sgbuf_ops_copy_playback,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -1037,8 +1038,6 @@ static snd_pcm_ops_t snd_via8233_multi_ops = {
.prepare = snd_via8233_multi_prepare,
.trigger = snd_via82xx_pcm_trigger,
.pointer = snd_via8233_pcm_pointer,
.copy = snd_pcm_sgbuf_ops_copy_playback,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -1052,8 +1051,6 @@ static snd_pcm_ops_t snd_via8233_capture_ops = {
.prepare = snd_via8233_capture_prepare,
.trigger = snd_via82xx_pcm_trigger,
.pointer = snd_via8233_pcm_pointer,
.copy = snd_pcm_sgbuf_ops_copy_capture,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
......@@ -1088,6 +1085,9 @@ static int __devinit snd_via8233_pcm_new(via82xx_t *chip)
chip->devs[chip->capture_devno].reg_offset = VIA_REG_CAPTURE_8233_STATUS;
chip->devs[chip->capture_devno].direction = 1;
if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm)) < 0)
return err;
/* PCM #1: multi-channel playback and 2nd capture */
err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 1, &pcm);
if (err < 0)
......@@ -1102,6 +1102,10 @@ static int __devinit snd_via8233_pcm_new(via82xx_t *chip)
/* set up capture */
chip->devs[chip->capture_devno + 1].reg_offset = VIA_REG_CAPTURE_8233_STATUS + 0x10;
chip->devs[chip->capture_devno + 1].direction = 1;
if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm)) < 0)
return err;
return 0;
}
......@@ -1133,6 +1137,9 @@ static int __devinit snd_via8233a_pcm_new(via82xx_t *chip)
chip->devs[chip->capture_devno].reg_offset = VIA_REG_CAPTURE_8233_STATUS;
chip->devs[chip->capture_devno].direction = 1;
if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm)) < 0)
return err;
/* PCM #1: DXS3 playback (for spdif) */
err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 0, &pcm);
if (err < 0)
......@@ -1143,6 +1150,10 @@ static int __devinit snd_via8233a_pcm_new(via82xx_t *chip)
/* set up playback */
chip->devs[chip->playback_devno].reg_offset = 0x30;
chip->devs[chip->playback_devno].direction = 0;
if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm)) < 0)
return err;
return 0;
}
......@@ -1169,6 +1180,10 @@ static int __devinit snd_via686_pcm_new(via82xx_t *chip)
chip->devs[0].direction = 0;
chip->devs[1].reg_offset = VIA_REG_CAPTURE_STATUS;
chip->devs[1].direction = 1;
if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm)) < 0)
return err;
return 0;
}
......@@ -1348,6 +1363,7 @@ static snd_kcontrol_new_t snd_via82xx_joystick_control __devinitdata = {
static int snd_via8233_init_misc(via82xx_t *chip, int dev)
{
int i, err, caps;
unsigned char val;
caps = chip->revision == VIA_REV_8233A ? 1 : 2;
for (i = 0; i < caps; i++) {
......@@ -1359,6 +1375,12 @@ static int snd_via8233_init_misc(via82xx_t *chip, int dev)
err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip));
if (err < 0)
return err;
/* select spdif data slot 10/11 */
pci_read_config_byte(chip->pci, 0x49, &val);
val &= ~0x03;
pci_write_config_byte(chip->pci, 0x49, val);
return 0;
}
......@@ -1583,7 +1605,8 @@ static int __devinit snd_via82xx_create(snd_card_t * card,
spin_lock_init(&chip->reg_lock);
spin_lock_init(&chip->ac97_lock);
spin_lock_init(&chip->rate_lock);
spin_lock_init(&chip->rates[0].lock);
spin_lock_init(&chip->rates[1].lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
......
......@@ -926,7 +926,7 @@ static int snd_ymfpci_playback_spdif_open(snd_pcm_substream_t * substream)
snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2);
ymfpci_open_extension(chip);
chip->spdif_pcm_bits = chip->spdif_bits;
snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
chip->spdif_opened++;
spin_unlock_irqrestore(&chip->reg_lock, flags);
......@@ -1314,8 +1314,8 @@ static int snd_ymfpci_spdif_mask_get(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_ymfpci_spdif_mask __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_ymfpci_spdif_mask_info,
.get = snd_ymfpci_spdif_mask_get,
};
......@@ -1362,8 +1362,8 @@ static int snd_ymfpci_spdif_stream_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_ymfpci_spdif_stream __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
.info = snd_ymfpci_spdif_stream_info,
.get = snd_ymfpci_spdif_stream_get,
.put = snd_ymfpci_spdif_stream_put
......
This diff is collapsed.
......@@ -139,6 +139,7 @@ struct snd_usb_audio {
struct list_head pcm_list; /* list of pcm streams */
int pcm_devs;
struct list_head midi_list; /* list of midi interfaces */
int next_midi_device;
};
......@@ -150,7 +151,8 @@ struct snd_usb_audio {
#define QUIRK_MIDI_FIXED_ENDPOINT 0
#define QUIRK_MIDI_YAMAHA 1
#define QUIRK_MIDI_MIDIMAN 2
#define QUIRK_ROLAND_UA100 3
#define QUIRK_COMPOSITE 3
#define QUIRK_AUDIO_FIXED_ENDPOINT 4
typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
......@@ -175,7 +177,10 @@ struct snd_usb_midi_endpoint_info {
/* for QUIRK_MIDI_MIDIMAN, data points to a snd_usb_midi_endpoint_info
* structure (out_cables and in_cables only) */
/* for QUIRK_ROLAND_UA100, data is NULL */
/* for QUIRK_COMPOSITE, data points to an array of snd_usb_audio_quirk
* structures, terminated with .ifnum = -1 */
/* for QUIRK_AUDIO_FIXED_ENDPOINT, data points to an audioformat structure */
/*
*/
......@@ -192,6 +197,7 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub
int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffer, int buflen);
int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk);
void snd_usbmidi_disconnect(struct list_head *p);
/*
* retrieve usb_interface descriptor from the host interface
......
......@@ -77,6 +77,7 @@ struct snd_usb_midi {
struct usb_interface *iface;
const snd_usb_audio_quirk_t *quirk;
snd_rawmidi_t* rmidi;
struct list_head list;
struct snd_usb_midi_endpoint {
snd_usb_midi_out_endpoint_t *out;
......@@ -394,7 +395,7 @@ static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep)
unsigned long flags;
spin_lock_irqsave(&ep->buffer_lock, flags);
if (urb->status == -EINPROGRESS) {
if (urb->status == -EINPROGRESS || ep->umidi->chip->shutdown) {
spin_unlock_irqrestore(&ep->buffer_lock, flags);
return;
}
......@@ -451,10 +452,8 @@ static void snd_usbmidi_output_trigger(snd_rawmidi_substream_t* substream, int u
usbmidi_out_port_t* port = (usbmidi_out_port_t*)substream->runtime->private_data;
port->active = up;
if (up) {
if (! port->ep->umidi->chip->shutdown) /* to be sure... */
tasklet_hi_schedule(&port->ep->tasklet);
}
if (up)
tasklet_hi_schedule(&port->ep->tasklet);
}
static int snd_usbmidi_input_open(snd_rawmidi_substream_t* substream)
......@@ -490,11 +489,8 @@ static snd_rawmidi_ops_t snd_usbmidi_input_ops = {
static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
{
if (ep->urb) {
if (ep->urb->transfer_buffer) {
if (! ep->umidi->chip->shutdown) /* to be sure */
usb_unlink_urb(ep->urb);
if (ep->urb->transfer_buffer)
kfree(ep->urb->transfer_buffer);
}
usb_free_urb(ep->urb);
}
snd_magic_kfree(ep);
......@@ -619,11 +615,8 @@ static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
if (ep->tasklet.func)
tasklet_kill(&ep->tasklet);
if (ep->urb) {
if (ep->urb->transfer_buffer) {
if (! ep->umidi->chip->shutdown) /* to be sure */
usb_unlink_urb(ep->urb);
if (ep->urb->transfer_buffer)
kfree(ep->urb->transfer_buffer);
}
usb_free_urb(ep->urb);
}
snd_magic_kfree(ep);
......@@ -693,6 +686,24 @@ static void snd_usbmidi_free(snd_usb_midi_t* umidi)
snd_magic_kfree(umidi);
}
/*
* Unlinks all URBs (must be done before the usb_device is deleted).
*/
void snd_usbmidi_disconnect(struct list_head* p)
{
snd_usb_midi_t* umidi;
int i;
umidi = list_entry(p, snd_usb_midi_t, list);
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
if (ep->out && ep->out->urb)
usb_unlink_urb(ep->out->urb);
if (ep->in && ep->in->urb)
usb_unlink_urb(ep->in->urb);
}
}
static void snd_usbmidi_rawmidi_free(snd_rawmidi_t* rmidi)
{
snd_usb_midi_t* umidi = snd_magic_cast(snd_usb_midi_t, rmidi->private_data, return);
......@@ -994,7 +1005,7 @@ static int snd_usbmidi_create_rawmidi(snd_usb_midi_t* umidi,
out_ports, in_ports, &rmidi);
if (err < 0)
return err;
strcpy(rmidi->name, umidi->chip->card->longname);
strcpy(rmidi->name, umidi->chip->card->shortname);
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
......@@ -1079,6 +1090,8 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
return err;
}
list_add(&umidi->list, &umidi->chip->midi_list);
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
if (umidi->endpoints[i].in)
snd_usbmidi_submit_urb(umidi->endpoints[i].in->urb,
......
......@@ -161,6 +161,15 @@
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE(0x0499, 0x1011),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "P-250",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE(0x0499, 0x1012),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
......@@ -233,8 +242,55 @@
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "UA-100",
.ifnum = 0,
.type = QUIRK_ROLAND_UA100
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = & (const snd_usb_audio_quirk_t[]) {
{
.ifnum = 0,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = & (const struct audioformat) {
.format = SNDRV_PCM_FORMAT_S16_LE,
.channels = 4,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.attributes = 0,
.endpoint = 0x01,
.ep_attr = 0x09,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 44100,
.rate_max = 44100,
}
},
{
.ifnum = 1,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = & (const struct audioformat) {
.format = SNDRV_PCM_FORMAT_S16_LE,
.channels = 2,
.iface = 1,
.altsetting = 1,
.altset_idx = 1,
.attributes = EP_CS_ATTR_FILL_MAX,
.endpoint = 0x81,
.ep_attr = 0x05,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 44100,
.rate_max = 44100,
}
},
{
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x0007,
.in_cables = 0x0007
}
},
{
.ifnum = -1
}
}
}
},
{
......@@ -342,15 +398,59 @@
}
},
{
/* thanks to Emiliano Grilli <emillo@libero.it> for helping researching this data */
USB_DEVICE(0x0582, 0x000c),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland",
.product_name = "SC-D70",
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x0007,
.in_cables = 0x0007
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = & (const snd_usb_audio_quirk_t[]) {
{
.ifnum = 0,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = & (const struct audioformat) {
.format = SNDRV_PCM_FORMAT_S24_3LE,
.channels = 2,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.attributes = 0,
.endpoint = 0x01,
.ep_attr = 0x01,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 44100,
.rate_max = 44100,
}
},
{
.ifnum = 1,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = & (const struct audioformat) {
.format = SNDRV_PCM_FORMAT_S24_3LE,
.channels = 2,
.iface = 1,
.altsetting = 1,
.altset_idx = 1,
.attributes = 0,
.endpoint = 0x81,
.ep_attr = 0x01,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 44100,
.rate_max = 44100,
}
},
{
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.out_cables = 0x0007,
.in_cables = 0x0007
}
},
{
.ifnum = -1
}
}
}
},
......
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