You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'topic/misc' into fix/misc
This commit is contained in:
@@ -237,8 +237,9 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
|
||||
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_TLV_READWRITE|
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
|
||||
kctl.info = ncontrol->info;
|
||||
kctl.get = ncontrol->get;
|
||||
kctl.put = ncontrol->put;
|
||||
@@ -1099,7 +1100,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
||||
|
||||
if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
|
||||
return -EFAULT;
|
||||
if (tlv.length < sizeof(unsigned int) * 3)
|
||||
if (tlv.length < sizeof(unsigned int) * 2)
|
||||
return -EINVAL;
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_numid(card, tlv.numid);
|
||||
|
||||
+32
-10
@@ -100,6 +100,35 @@ EXPORT_SYMBOL_GPL(__snd_printk);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include <linux/pci.h>
|
||||
/**
|
||||
* snd_pci_quirk_lookup_id - look up a PCI SSID quirk list
|
||||
* @vendor: PCI SSV id
|
||||
* @device: PCI SSD id
|
||||
* @list: quirk list, terminated by a null entry
|
||||
*
|
||||
* Look through the given quirk list and finds a matching entry
|
||||
* with the same PCI SSID. When subdevice is 0, all subdevice
|
||||
* values may match.
|
||||
*
|
||||
* Returns the matched entry pointer, or NULL if nothing matched.
|
||||
*/
|
||||
const struct snd_pci_quirk *
|
||||
snd_pci_quirk_lookup_id(u16 vendor, u16 device,
|
||||
const struct snd_pci_quirk *list)
|
||||
{
|
||||
const struct snd_pci_quirk *q;
|
||||
|
||||
for (q = list; q->subvendor; q++) {
|
||||
if (q->subvendor != vendor)
|
||||
continue;
|
||||
if (!q->subdevice ||
|
||||
(device & q->subdevice_mask) == q->subdevice)
|
||||
return q;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pci_quirk_lookup_id);
|
||||
|
||||
/**
|
||||
* snd_pci_quirk_lookup - look up a PCI SSID quirk list
|
||||
* @pci: pci_dev handle
|
||||
@@ -114,16 +143,9 @@ EXPORT_SYMBOL_GPL(__snd_printk);
|
||||
const struct snd_pci_quirk *
|
||||
snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
|
||||
{
|
||||
const struct snd_pci_quirk *q;
|
||||
|
||||
for (q = list; q->subvendor; q++) {
|
||||
if (q->subvendor != pci->subsystem_vendor)
|
||||
continue;
|
||||
if (!q->subdevice ||
|
||||
(pci->subsystem_device & q->subdevice_mask) == q->subdevice)
|
||||
return q;
|
||||
}
|
||||
return NULL;
|
||||
return snd_pci_quirk_lookup_id(pci->subsystem_vendor,
|
||||
pci->subsystem_device,
|
||||
list);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pci_quirk_lookup);
|
||||
#endif
|
||||
|
||||
@@ -632,6 +632,12 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
|
||||
return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
|
||||
}
|
||||
|
||||
static inline
|
||||
snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
|
||||
{
|
||||
return runtime->hw_ptr_interrupt;
|
||||
}
|
||||
|
||||
/* define extended formats in the recent OSS versions (if any) */
|
||||
/* linear formats */
|
||||
#define AFMT_S32_LE 0x00001000
|
||||
@@ -1102,7 +1108,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
|
||||
return err;
|
||||
}
|
||||
runtime->oss.prepare = 0;
|
||||
runtime->oss.prev_hw_ptr_interrupt = 0;
|
||||
runtime->oss.prev_hw_ptr_period = 0;
|
||||
runtime->oss.period_ptr = 0;
|
||||
runtime->oss.buffer_used = 0;
|
||||
|
||||
@@ -1950,7 +1956,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr)
|
||||
static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream,
|
||||
snd_pcm_uframes_t hw_ptr)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_uframes_t appl_ptr;
|
||||
@@ -1986,7 +1993,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
|
||||
if (runtime->oss.trigger)
|
||||
goto _skip1;
|
||||
if (atomic_read(&psubstream->mmap_count))
|
||||
snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
|
||||
snd_pcm_oss_simulate_fill(psubstream,
|
||||
get_hw_ptr_period(runtime));
|
||||
runtime->oss.trigger = 1;
|
||||
runtime->start_threshold = 1;
|
||||
cmd = SNDRV_PCM_IOCTL_START;
|
||||
@@ -2105,11 +2113,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
|
||||
info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
|
||||
if (atomic_read(&substream->mmap_count)) {
|
||||
snd_pcm_sframes_t n;
|
||||
n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
|
||||
delay = get_hw_ptr_period(runtime);
|
||||
n = delay - runtime->oss.prev_hw_ptr_period;
|
||||
if (n < 0)
|
||||
n += runtime->boundary;
|
||||
info.blocks = n / runtime->period_size;
|
||||
runtime->oss.prev_hw_ptr_interrupt = delay;
|
||||
runtime->oss.prev_hw_ptr_period = delay;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
snd_pcm_oss_simulate_fill(substream, delay);
|
||||
info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
|
||||
@@ -2673,18 +2682,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
if (atomic_read(&substream->mmap_count))
|
||||
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
|
||||
return runtime->oss.prev_hw_ptr_period !=
|
||||
get_hw_ptr_period(runtime);
|
||||
else
|
||||
return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
|
||||
return snd_pcm_playback_avail(runtime) >=
|
||||
runtime->oss.period_frames;
|
||||
}
|
||||
|
||||
static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
if (atomic_read(&substream->mmap_count))
|
||||
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
|
||||
return runtime->oss.prev_hw_ptr_period !=
|
||||
get_hw_ptr_period(runtime);
|
||||
else
|
||||
return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
|
||||
return snd_pcm_capture_avail(runtime) >=
|
||||
runtime->oss.period_frames;
|
||||
}
|
||||
|
||||
static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
|
||||
|
||||
@@ -894,6 +894,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
|
||||
memset((void*)runtime->control, 0, size);
|
||||
|
||||
init_waitqueue_head(&runtime->sleep);
|
||||
init_waitqueue_head(&runtime->tsleep);
|
||||
|
||||
runtime->status->state = SNDRV_PCM_STATE_OPEN;
|
||||
|
||||
@@ -921,6 +922,10 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
|
||||
snd_free_pages((void*)runtime->control,
|
||||
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
|
||||
kfree(runtime->hw_constraints.rules);
|
||||
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
||||
if (runtime->hwptr_log)
|
||||
kfree(runtime->hwptr_log);
|
||||
#endif
|
||||
kfree(runtime);
|
||||
substream->runtime = NULL;
|
||||
put_pid(substream->pid);
|
||||
|
||||
+246
-201
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@
|
||||
#include <linux/time.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/info.h>
|
||||
@@ -434,3 +435,57 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_lib_free_pages);
|
||||
|
||||
int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
|
||||
size_t size, gfp_t gfp_flags)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
||||
if (PCM_RUNTIME_CHECK(substream))
|
||||
return -EINVAL;
|
||||
runtime = substream->runtime;
|
||||
if (runtime->dma_area) {
|
||||
if (runtime->dma_bytes >= size)
|
||||
return 0; /* already large enough */
|
||||
vfree(runtime->dma_area);
|
||||
}
|
||||
runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL);
|
||||
if (!runtime->dma_area)
|
||||
return -ENOMEM;
|
||||
runtime->dma_bytes = size;
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
|
||||
|
||||
/**
|
||||
* snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer
|
||||
* @substream: the substream with a buffer allocated by
|
||||
* snd_pcm_lib_alloc_vmalloc_buffer()
|
||||
*/
|
||||
int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime;
|
||||
|
||||
if (PCM_RUNTIME_CHECK(substream))
|
||||
return -EINVAL;
|
||||
runtime = substream->runtime;
|
||||
vfree(runtime->dma_area);
|
||||
runtime->dma_area = NULL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
|
||||
|
||||
/**
|
||||
* snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct
|
||||
* @substream: the substream with a buffer allocated by
|
||||
* snd_pcm_lib_alloc_vmalloc_buffer()
|
||||
* @offset: offset in the buffer
|
||||
*
|
||||
* This function is to be used as the page callback in the PCM ops.
|
||||
*/
|
||||
struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
|
||||
unsigned long offset)
|
||||
{
|
||||
return vmalloc_to_page(substream->runtime->dma_area + offset);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page);
|
||||
|
||||
+52
-7
@@ -27,6 +27,7 @@
|
||||
#include <linux/pm_qos_params.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/math64.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/info.h>
|
||||
@@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
|
||||
return usecs;
|
||||
}
|
||||
|
||||
static int calc_boundary(struct snd_pcm_runtime *runtime)
|
||||
{
|
||||
u_int64_t boundary;
|
||||
|
||||
boundary = (u_int64_t)runtime->buffer_size *
|
||||
(u_int64_t)runtime->period_size;
|
||||
#if BITS_PER_LONG < 64
|
||||
/* try to find lowest common multiple for buffer and period */
|
||||
if (boundary > LONG_MAX - runtime->buffer_size) {
|
||||
u_int32_t remainder = -1;
|
||||
u_int32_t divident = runtime->buffer_size;
|
||||
u_int32_t divisor = runtime->period_size;
|
||||
while (remainder) {
|
||||
remainder = divident % divisor;
|
||||
if (remainder) {
|
||||
divident = divisor;
|
||||
divisor = remainder;
|
||||
}
|
||||
}
|
||||
boundary = div_u64(boundary, divisor);
|
||||
if (boundary > LONG_MAX - runtime->buffer_size)
|
||||
return -ERANGE;
|
||||
}
|
||||
#endif
|
||||
if (boundary == 0)
|
||||
return -ERANGE;
|
||||
runtime->boundary = boundary;
|
||||
while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
|
||||
runtime->boundary *= 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
@@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
runtime->stop_threshold = runtime->buffer_size;
|
||||
runtime->silence_threshold = 0;
|
||||
runtime->silence_size = 0;
|
||||
runtime->boundary = runtime->buffer_size;
|
||||
while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
|
||||
runtime->boundary *= 2;
|
||||
err = calc_boundary(runtime);
|
||||
if (err < 0)
|
||||
goto _error;
|
||||
|
||||
snd_pcm_timer_resolution_change(substream);
|
||||
runtime->status->state = SNDRV_PCM_STATE_SETUP;
|
||||
@@ -516,6 +549,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_sw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime;
|
||||
int err;
|
||||
|
||||
if (PCM_RUNTIME_CHECK(substream))
|
||||
return -ENXIO;
|
||||
@@ -540,6 +574,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
|
||||
if (params->silence_threshold > runtime->buffer_size)
|
||||
return -EINVAL;
|
||||
}
|
||||
err = 0;
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
runtime->tstamp_mode = params->tstamp_mode;
|
||||
runtime->period_step = params->period_step;
|
||||
@@ -553,10 +588,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
runtime->silence_size > 0)
|
||||
snd_pcm_playback_silence(substream, ULONG_MAX);
|
||||
wake_up(&runtime->sleep);
|
||||
err = snd_pcm_update_state(substream, runtime);
|
||||
}
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
|
||||
@@ -917,6 +952,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
|
||||
runtime->status->state = state;
|
||||
}
|
||||
wake_up(&runtime->sleep);
|
||||
wake_up(&runtime->tsleep);
|
||||
}
|
||||
|
||||
static struct action_ops snd_pcm_action_stop = {
|
||||
@@ -1002,6 +1038,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
|
||||
SNDRV_TIMER_EVENT_MPAUSE,
|
||||
&runtime->trigger_tstamp);
|
||||
wake_up(&runtime->sleep);
|
||||
wake_up(&runtime->tsleep);
|
||||
} else {
|
||||
runtime->status->state = SNDRV_PCM_STATE_RUNNING;
|
||||
if (substream->timer)
|
||||
@@ -1059,6 +1096,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
|
||||
runtime->status->suspended_state = runtime->status->state;
|
||||
runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
|
||||
wake_up(&runtime->sleep);
|
||||
wake_up(&runtime->tsleep);
|
||||
}
|
||||
|
||||
static struct action_ops snd_pcm_action_suspend = {
|
||||
@@ -3162,9 +3200,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
|
||||
long size;
|
||||
unsigned long offset;
|
||||
|
||||
#ifdef pgprot_noncached
|
||||
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
|
||||
#endif
|
||||
area->vm_flags |= VM_IO;
|
||||
size = area->vm_end - area->vm_start;
|
||||
offset = area->vm_pgoff << PAGE_SHIFT;
|
||||
@@ -3178,6 +3214,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
|
||||
EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
|
||||
#endif /* SNDRV_PCM_INFO_MMAP */
|
||||
|
||||
/* mmap callback with pgprot_noncached */
|
||||
int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area)
|
||||
{
|
||||
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
|
||||
return snd_pcm_default_mmap(substream, area);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached);
|
||||
|
||||
/*
|
||||
* mmap DMA buffer
|
||||
*/
|
||||
|
||||
@@ -2190,7 +2190,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
|
||||
if (p->cmd == cmd)
|
||||
return p->func(client, arg);
|
||||
}
|
||||
snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n",
|
||||
snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
|
||||
cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
+13
-14
@@ -33,22 +33,21 @@
|
||||
|
||||
#define SKEW_BASE 0x10000 /* 16bit shift */
|
||||
|
||||
static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer_tick *tick,
|
||||
int tempo, int ppq)
|
||||
static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
|
||||
{
|
||||
if (tempo < 1000000)
|
||||
tick->resolution = (tempo * 1000) / ppq;
|
||||
if (tmr->tempo < 1000000)
|
||||
tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
|
||||
else {
|
||||
/* might overflow.. */
|
||||
unsigned int s;
|
||||
s = tempo % ppq;
|
||||
s = (s * 1000) / ppq;
|
||||
tick->resolution = (tempo / ppq) * 1000;
|
||||
tick->resolution += s;
|
||||
s = tmr->tempo % tmr->ppq;
|
||||
s = (s * 1000) / tmr->ppq;
|
||||
tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
|
||||
tmr->tick.resolution += s;
|
||||
}
|
||||
if (tick->resolution <= 0)
|
||||
tick->resolution = 1;
|
||||
snd_seq_timer_update_tick(tick, 0);
|
||||
if (tmr->tick.resolution <= 0)
|
||||
tmr->tick.resolution = 1;
|
||||
snd_seq_timer_update_tick(&tmr->tick, 0);
|
||||
}
|
||||
|
||||
/* create new timer (constructor) */
|
||||
@@ -96,7 +95,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
|
||||
/* setup defaults */
|
||||
tmr->ppq = 96; /* 96 PPQ */
|
||||
tmr->tempo = 500000; /* 120 BPM */
|
||||
snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
|
||||
snd_seq_timer_set_tick_resolution(tmr);
|
||||
tmr->running = 0;
|
||||
|
||||
tmr->type = SNDRV_SEQ_TIMER_ALSA;
|
||||
@@ -180,7 +179,7 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
|
||||
spin_lock_irqsave(&tmr->lock, flags);
|
||||
if ((unsigned int)tempo != tmr->tempo) {
|
||||
tmr->tempo = tempo;
|
||||
snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
|
||||
snd_seq_timer_set_tick_resolution(tmr);
|
||||
}
|
||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
||||
return 0;
|
||||
@@ -205,7 +204,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq)
|
||||
}
|
||||
|
||||
tmr->ppq = ppq;
|
||||
snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq);
|
||||
snd_seq_timer_set_tick_resolution(tmr);
|
||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1
-1
@@ -393,7 +393,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
|
||||
event == SNDRV_TIMER_EVENT_CONTINUE)
|
||||
resolution = snd_timer_resolution(ti);
|
||||
if (ti->ccallback)
|
||||
ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution);
|
||||
ti->ccallback(ti, event, &tstamp, resolution);
|
||||
if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
|
||||
return;
|
||||
timer = ti->timer;
|
||||
|
||||
+180
-110
@@ -45,109 +45,23 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
|
||||
#define MAX_PCM_SUBSTREAMS 128
|
||||
#define MAX_MIDI_DEVICES 2
|
||||
|
||||
#if 0 /* emu10k1 emulation */
|
||||
#define MAX_BUFFER_SIZE (128 * 1024)
|
||||
static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
|
||||
{
|
||||
int err;
|
||||
err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
#define add_playback_constraints emu10k1_playback_constraints
|
||||
#endif
|
||||
|
||||
#if 0 /* RME9652 emulation */
|
||||
#define MAX_BUFFER_SIZE (26 * 64 * 1024)
|
||||
#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE
|
||||
#define USE_CHANNELS_MIN 26
|
||||
#define USE_CHANNELS_MAX 26
|
||||
#define USE_PERIODS_MIN 2
|
||||
#define USE_PERIODS_MAX 2
|
||||
#endif
|
||||
|
||||
#if 0 /* ICE1712 emulation */
|
||||
#define MAX_BUFFER_SIZE (256 * 1024)
|
||||
#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE
|
||||
#define USE_CHANNELS_MIN 10
|
||||
#define USE_CHANNELS_MAX 10
|
||||
#define USE_PERIODS_MIN 1
|
||||
#define USE_PERIODS_MAX 1024
|
||||
#endif
|
||||
|
||||
#if 0 /* UDA1341 emulation */
|
||||
#define MAX_BUFFER_SIZE (16380)
|
||||
#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
||||
#define USE_CHANNELS_MIN 2
|
||||
#define USE_CHANNELS_MAX 2
|
||||
#define USE_PERIODS_MIN 2
|
||||
#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
|
||||
|
||||
#if 0 /* CA0106 */
|
||||
#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|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000)
|
||||
#define USE_RATE_MIN 48000
|
||||
#define USE_RATE_MAX 192000
|
||||
#define MAX_BUFFER_SIZE ((65536-64)*8)
|
||||
#define MAX_PERIOD_SIZE (65536-64)
|
||||
#define USE_PERIODS_MIN 2
|
||||
#define USE_PERIODS_MAX 8
|
||||
#endif
|
||||
|
||||
|
||||
/* defaults */
|
||||
#ifndef MAX_BUFFER_SIZE
|
||||
#define MAX_BUFFER_SIZE (64*1024)
|
||||
#endif
|
||||
#ifndef MAX_PERIOD_SIZE
|
||||
#define MIN_PERIOD_SIZE 64
|
||||
#define MAX_PERIOD_SIZE MAX_BUFFER_SIZE
|
||||
#endif
|
||||
#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
|
||||
#ifndef USE_CHANNELS_MAX
|
||||
#define USE_CHANNELS_MAX 2
|
||||
#endif
|
||||
#ifndef USE_PERIODS_MIN
|
||||
#define USE_PERIODS_MIN 1
|
||||
#endif
|
||||
#ifndef USE_PERIODS_MAX
|
||||
#define USE_PERIODS_MAX 1024
|
||||
#endif
|
||||
#ifndef add_playback_constraints
|
||||
#define add_playback_constraints(x) 0
|
||||
#endif
|
||||
#ifndef add_capture_constraints
|
||||
#define add_capture_constraints(x) 0
|
||||
#endif
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
||||
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
|
||||
static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL};
|
||||
static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
|
||||
static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
|
||||
//static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
|
||||
@@ -162,6 +76,8 @@ module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
|
||||
module_param_array(model, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(model, "Soundcard model.");
|
||||
module_param_array(pcm_devs, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
|
||||
module_param_array(pcm_substreams, int, NULL, 0444);
|
||||
@@ -193,15 +109,120 @@ struct dummy_timer_ops {
|
||||
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
|
||||
};
|
||||
|
||||
struct dummy_model {
|
||||
const char *name;
|
||||
int (*playback_constraints)(struct snd_pcm_runtime *runtime);
|
||||
int (*capture_constraints)(struct snd_pcm_runtime *runtime);
|
||||
u64 formats;
|
||||
size_t buffer_bytes_max;
|
||||
size_t period_bytes_min;
|
||||
size_t period_bytes_max;
|
||||
unsigned int periods_min;
|
||||
unsigned int periods_max;
|
||||
unsigned int rates;
|
||||
unsigned int rate_min;
|
||||
unsigned int rate_max;
|
||||
unsigned int channels_min;
|
||||
unsigned int channels_max;
|
||||
};
|
||||
|
||||
struct snd_dummy {
|
||||
struct snd_card *card;
|
||||
struct dummy_model *model;
|
||||
struct snd_pcm *pcm;
|
||||
struct snd_pcm_hardware pcm_hw;
|
||||
spinlock_t mixer_lock;
|
||||
int mixer_volume[MIXER_ADDR_LAST+1][2];
|
||||
int capture_source[MIXER_ADDR_LAST+1][2];
|
||||
const struct dummy_timer_ops *timer_ops;
|
||||
};
|
||||
|
||||
/*
|
||||
* card models
|
||||
*/
|
||||
|
||||
static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
|
||||
{
|
||||
int err;
|
||||
err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dummy_model model_emu10k1 = {
|
||||
.name = "emu10k1",
|
||||
.playback_constraints = emu10k1_playback_constraints,
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
};
|
||||
|
||||
struct dummy_model model_rme9652 = {
|
||||
.name = "rme9652",
|
||||
.buffer_bytes_max = 26 * 64 * 1024,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels_min = 26,
|
||||
.channels_max = 26,
|
||||
.periods_min = 2,
|
||||
.periods_max = 2,
|
||||
};
|
||||
|
||||
struct dummy_model model_ice1712 = {
|
||||
.name = "ice1712",
|
||||
.buffer_bytes_max = 256 * 1024,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels_min = 10,
|
||||
.channels_max = 10,
|
||||
.periods_min = 1,
|
||||
.periods_max = 1024,
|
||||
};
|
||||
|
||||
struct dummy_model model_uda1341 = {
|
||||
.name = "uda1341",
|
||||
.buffer_bytes_max = 16380,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.periods_min = 2,
|
||||
.periods_max = 255,
|
||||
};
|
||||
|
||||
struct dummy_model model_ac97 = {
|
||||
.name = "ac97",
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
};
|
||||
|
||||
struct dummy_model model_ca0106 = {
|
||||
.name = "ca0106",
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.buffer_bytes_max = ((65536-64)*8),
|
||||
.period_bytes_max = (65536-64),
|
||||
.periods_min = 2,
|
||||
.periods_max = 8,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 192000,
|
||||
};
|
||||
|
||||
struct dummy_model *dummy_models[] = {
|
||||
&model_emu10k1,
|
||||
&model_rme9652,
|
||||
&model_ice1712,
|
||||
&model_uda1341,
|
||||
&model_ac97,
|
||||
&model_ca0106,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* system timer interface
|
||||
*/
|
||||
@@ -509,7 +530,7 @@ static struct snd_pcm_hardware dummy_pcm_hardware = {
|
||||
.channels_min = USE_CHANNELS_MIN,
|
||||
.channels_max = USE_CHANNELS_MAX,
|
||||
.buffer_bytes_max = MAX_BUFFER_SIZE,
|
||||
.period_bytes_min = 64,
|
||||
.period_bytes_min = MIN_PERIOD_SIZE,
|
||||
.period_bytes_max = MAX_PERIOD_SIZE,
|
||||
.periods_min = USE_PERIODS_MIN,
|
||||
.periods_max = USE_PERIODS_MAX,
|
||||
@@ -538,6 +559,7 @@ static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
static int dummy_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
|
||||
struct dummy_model *model = dummy->model;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int err;
|
||||
|
||||
@@ -551,7 +573,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
runtime->hw = dummy_pcm_hardware;
|
||||
runtime->hw = dummy->pcm_hw;
|
||||
if (substream->pcm->device & 1) {
|
||||
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
|
||||
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
|
||||
@@ -560,10 +582,16 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
|
||||
runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
err = add_playback_constraints(substream->runtime);
|
||||
else
|
||||
err = add_capture_constraints(substream->runtime);
|
||||
if (model == NULL)
|
||||
return 0;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (model->playback_constraints)
|
||||
err = model->playback_constraints(substream->runtime);
|
||||
} else {
|
||||
if (model->capture_constraints)
|
||||
err = model->capture_constraints(substream->runtime);
|
||||
}
|
||||
if (err < 0) {
|
||||
dummy->timer_ops->free(substream);
|
||||
return err;
|
||||
@@ -823,17 +851,19 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy)
|
||||
/*
|
||||
* proc interface
|
||||
*/
|
||||
static void print_formats(struct snd_info_buffer *buffer)
|
||||
static void print_formats(struct snd_dummy *dummy,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
|
||||
if (dummy_pcm_hardware.formats & (1ULL << i))
|
||||
if (dummy->pcm_hw.formats & (1ULL << i))
|
||||
snd_iprintf(buffer, " %s", snd_pcm_format_name(i));
|
||||
}
|
||||
}
|
||||
|
||||
static void print_rates(struct snd_info_buffer *buffer)
|
||||
static void print_rates(struct snd_dummy *dummy,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
static int rates[] = {
|
||||
5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
|
||||
@@ -841,19 +871,19 @@ static void print_rates(struct snd_info_buffer *buffer)
|
||||
};
|
||||
int i;
|
||||
|
||||
if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS)
|
||||
if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS)
|
||||
snd_iprintf(buffer, " continuous");
|
||||
if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT)
|
||||
if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT)
|
||||
snd_iprintf(buffer, " knot");
|
||||
for (i = 0; i < ARRAY_SIZE(rates); i++)
|
||||
if (dummy_pcm_hardware.rates & (1 << i))
|
||||
if (dummy->pcm_hw.rates & (1 << i))
|
||||
snd_iprintf(buffer, " %d", rates[i]);
|
||||
}
|
||||
|
||||
#define get_dummy_int_ptr(ofs) \
|
||||
(unsigned int *)((char *)&dummy_pcm_hardware + (ofs))
|
||||
#define get_dummy_ll_ptr(ofs) \
|
||||
(unsigned long long *)((char *)&dummy_pcm_hardware + (ofs))
|
||||
#define get_dummy_int_ptr(dummy, ofs) \
|
||||
(unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs))
|
||||
#define get_dummy_ll_ptr(dummy, ofs) \
|
||||
(unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs))
|
||||
|
||||
struct dummy_hw_field {
|
||||
const char *name;
|
||||
@@ -884,20 +914,21 @@ static struct dummy_hw_field fields[] = {
|
||||
static void dummy_proc_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_dummy *dummy = entry->private_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fields); i++) {
|
||||
snd_iprintf(buffer, "%s ", fields[i].name);
|
||||
if (fields[i].size == sizeof(int))
|
||||
snd_iprintf(buffer, fields[i].format,
|
||||
*get_dummy_int_ptr(fields[i].offset));
|
||||
*get_dummy_int_ptr(dummy, fields[i].offset));
|
||||
else
|
||||
snd_iprintf(buffer, fields[i].format,
|
||||
*get_dummy_ll_ptr(fields[i].offset));
|
||||
*get_dummy_ll_ptr(dummy, fields[i].offset));
|
||||
if (!strcmp(fields[i].name, "formats"))
|
||||
print_formats(buffer);
|
||||
print_formats(dummy, buffer);
|
||||
else if (!strcmp(fields[i].name, "rates"))
|
||||
print_rates(buffer);
|
||||
print_rates(dummy, buffer);
|
||||
snd_iprintf(buffer, "\n");
|
||||
}
|
||||
}
|
||||
@@ -905,6 +936,7 @@ static void dummy_proc_read(struct snd_info_entry *entry,
|
||||
static void dummy_proc_write(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_dummy *dummy = entry->private_data;
|
||||
char line[64];
|
||||
|
||||
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||
@@ -924,9 +956,9 @@ static void dummy_proc_write(struct snd_info_entry *entry,
|
||||
if (strict_strtoull(item, 0, &val))
|
||||
continue;
|
||||
if (fields[i].size == sizeof(int))
|
||||
*get_dummy_int_ptr(fields[i].offset) = val;
|
||||
*get_dummy_int_ptr(dummy, fields[i].offset) = val;
|
||||
else
|
||||
*get_dummy_ll_ptr(fields[i].offset) = val;
|
||||
*get_dummy_ll_ptr(dummy, fields[i].offset) = val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,6 +970,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip)
|
||||
snd_info_set_text_ops(entry, chip, dummy_proc_read);
|
||||
entry->c.text.write = dummy_proc_write;
|
||||
entry->mode |= S_IWUSR;
|
||||
entry->private_data = chip;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -948,6 +981,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
|
||||
{
|
||||
struct snd_card *card;
|
||||
struct snd_dummy *dummy;
|
||||
struct dummy_model *m = NULL, **mdl;
|
||||
int idx, err;
|
||||
int dev = devptr->id;
|
||||
|
||||
@@ -957,6 +991,15 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
|
||||
return err;
|
||||
dummy = card->private_data;
|
||||
dummy->card = card;
|
||||
for (mdl = dummy_models; *mdl && model[dev]; mdl++) {
|
||||
if (strcmp(model[dev], (*mdl)->name) == 0) {
|
||||
printk(KERN_INFO
|
||||
"snd-dummy: Using model '%s' for card %i\n",
|
||||
(*mdl)->name, card->number);
|
||||
m = dummy->model = *mdl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
|
||||
if (pcm_substreams[dev] < 1)
|
||||
pcm_substreams[dev] = 1;
|
||||
@@ -966,6 +1009,33 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
|
||||
if (err < 0)
|
||||
goto __nodev;
|
||||
}
|
||||
|
||||
dummy->pcm_hw = dummy_pcm_hardware;
|
||||
if (m) {
|
||||
if (m->formats)
|
||||
dummy->pcm_hw.formats = m->formats;
|
||||
if (m->buffer_bytes_max)
|
||||
dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max;
|
||||
if (m->period_bytes_min)
|
||||
dummy->pcm_hw.period_bytes_min = m->period_bytes_min;
|
||||
if (m->period_bytes_max)
|
||||
dummy->pcm_hw.period_bytes_max = m->period_bytes_max;
|
||||
if (m->periods_min)
|
||||
dummy->pcm_hw.periods_min = m->periods_min;
|
||||
if (m->periods_max)
|
||||
dummy->pcm_hw.periods_max = m->periods_max;
|
||||
if (m->rates)
|
||||
dummy->pcm_hw.rates = m->rates;
|
||||
if (m->rate_min)
|
||||
dummy->pcm_hw.rate_min = m->rate_min;
|
||||
if (m->rate_max)
|
||||
dummy->pcm_hw.rate_max = m->rate_max;
|
||||
if (m->channels_min)
|
||||
dummy->pcm_hw.channels_min = m->channels_min;
|
||||
if (m->channels_max)
|
||||
dummy->pcm_hw.channels_max = m->channels_max;
|
||||
}
|
||||
|
||||
err = snd_card_dummy_new_mixer(dummy);
|
||||
if (err < 0)
|
||||
goto __nodev;
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/asoundef.h>
|
||||
@@ -55,55 +54,6 @@
|
||||
#include "vx_cmd.h"
|
||||
|
||||
|
||||
/*
|
||||
* we use a vmalloc'ed (sg-)buffer
|
||||
*/
|
||||
|
||||
/* get the physical page pointer on the given offset */
|
||||
static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
|
||||
unsigned long offset)
|
||||
{
|
||||
void *pageptr = subs->runtime->dma_area + offset;
|
||||
return vmalloc_to_page(pageptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a buffer via vmalloc_32().
|
||||
* called from hw_params
|
||||
* NOTE: this may be called not only once per pcm open!
|
||||
*/
|
||||
static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = subs->runtime;
|
||||
if (runtime->dma_area) {
|
||||
/* already allocated */
|
||||
if (runtime->dma_bytes >= size)
|
||||
return 0; /* already enough large */
|
||||
vfree(runtime->dma_area);
|
||||
}
|
||||
runtime->dma_area = vmalloc_32(size);
|
||||
if (! runtime->dma_area)
|
||||
return -ENOMEM;
|
||||
memset(runtime->dma_area, 0, size);
|
||||
runtime->dma_bytes = size;
|
||||
return 1; /* changed */
|
||||
}
|
||||
|
||||
/*
|
||||
* free the buffer.
|
||||
* called from hw_free callback
|
||||
* NOTE: this may be called not only once per pcm open!
|
||||
*/
|
||||
static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = subs->runtime;
|
||||
|
||||
vfree(runtime->dma_area);
|
||||
runtime->dma_area = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read three pending pcm bytes via inb()
|
||||
*/
|
||||
@@ -865,7 +815,8 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs)
|
||||
static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));
|
||||
return snd_pcm_lib_alloc_vmalloc_32_buffer
|
||||
(subs, params_buffer_bytes(hw_params));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -873,7 +824,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
|
||||
*/
|
||||
static int vx_pcm_hw_free(struct snd_pcm_substream *subs)
|
||||
{
|
||||
return snd_pcm_free_vmalloc_buffer(subs);
|
||||
return snd_pcm_lib_free_vmalloc_buffer(subs);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -953,7 +904,8 @@ static struct snd_pcm_ops vx_pcm_playback_ops = {
|
||||
.prepare = vx_pcm_prepare,
|
||||
.trigger = vx_pcm_trigger,
|
||||
.pointer = vx_pcm_playback_pointer,
|
||||
.page = snd_pcm_get_vmalloc_page,
|
||||
.page = snd_pcm_lib_get_vmalloc_page,
|
||||
.mmap = snd_pcm_lib_mmap_vmalloc,
|
||||
};
|
||||
|
||||
|
||||
@@ -1173,7 +1125,8 @@ static struct snd_pcm_ops vx_pcm_capture_ops = {
|
||||
.prepare = vx_pcm_prepare,
|
||||
.trigger = vx_pcm_trigger,
|
||||
.pointer = vx_pcm_capture_pointer,
|
||||
.page = snd_pcm_get_vmalloc_page,
|
||||
.page = snd_pcm_lib_get_vmalloc_page,
|
||||
.mmap = snd_pcm_lib_mmap_vmalloc,
|
||||
};
|
||||
|
||||
|
||||
|
||||
+20
-17
@@ -63,15 +63,16 @@ config SND_AD1848
|
||||
will be called snd-ad1848.
|
||||
|
||||
config SND_ALS100
|
||||
tristate "Avance Logic ALS100/ALS120"
|
||||
tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx"
|
||||
depends on PNP
|
||||
select ISAPNP
|
||||
select SND_OPL3_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_SB16_DSP
|
||||
help
|
||||
Say Y here to include support for soundcards based on Avance
|
||||
Logic ALS100, ALS110, ALS120 and ALS200 chips.
|
||||
Say Y here to include support for soundcards based on the
|
||||
Diamond Technologies DT-019X or Avance Logic chips: ALS007,
|
||||
ALS100, ALS110, ALS120 and ALS200 chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-als100.
|
||||
@@ -127,20 +128,6 @@ config SND_CS4236
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-cs4236.
|
||||
|
||||
config SND_DT019X
|
||||
tristate "Diamond Technologies DT-019X, Avance Logic ALS-007"
|
||||
depends on PNP
|
||||
select ISAPNP
|
||||
select SND_OPL3_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_SB16_DSP
|
||||
help
|
||||
Say Y here to include support for soundcards based on the
|
||||
Diamond Technologies DT-019X or Avance Logic ALS-007 chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-dt019x.
|
||||
|
||||
config SND_ES968
|
||||
tristate "Generic ESS ES968 driver"
|
||||
depends on PNP
|
||||
@@ -252,6 +239,22 @@ config SND_INTERWAVE_STB
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-interwave-stb.
|
||||
|
||||
config SND_JAZZ16
|
||||
tristate "Media Vision Jazz16 card and compatibles"
|
||||
select SND_OPL3_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_SB8_DSP
|
||||
help
|
||||
Say Y here to include support for soundcards based on the
|
||||
Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16),
|
||||
codec MVA416 (CS4216) and mixer MVA514 (ICS2514).
|
||||
Media Vision's Jazz16 cards were sold under names Pro Sonic 16,
|
||||
Premium 3-D and Pro 3-D. There were also OEMs cards with the
|
||||
Jazz16 chipset.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-jazz16.
|
||||
|
||||
config SND_OPL3SA2
|
||||
tristate "Yamaha OPL3-SA2/SA3"
|
||||
select SND_OPL3_LIB
|
||||
|
||||
@@ -7,7 +7,6 @@ snd-adlib-objs := adlib.o
|
||||
snd-als100-objs := als100.o
|
||||
snd-azt2320-objs := azt2320.o
|
||||
snd-cmi8330-objs := cmi8330.o
|
||||
snd-dt019x-objs := dt019x.o
|
||||
snd-es18xx-objs := es18xx.o
|
||||
snd-opl3sa2-objs := opl3sa2.o
|
||||
snd-sc6000-objs := sc6000.o
|
||||
@@ -19,7 +18,6 @@ obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
|
||||
obj-$(CONFIG_SND_ALS100) += snd-als100.o
|
||||
obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
|
||||
obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
|
||||
obj-$(CONFIG_SND_DT019X) += snd-dt019x.o
|
||||
obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
|
||||
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
|
||||
obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
|
||||
|
||||
+86
-35
@@ -2,9 +2,13 @@
|
||||
/*
|
||||
card-als100.c - driver for Avance Logic ALS100 based soundcards.
|
||||
Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
|
||||
Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it>
|
||||
|
||||
Thanks to Pierfrancesco 'qM2' Passerini.
|
||||
|
||||
Generalised for soundcards based on DT-0196 and ALS-007 chips
|
||||
by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
@@ -33,10 +37,10 @@
|
||||
|
||||
#define PFX "als100: "
|
||||
|
||||
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
|
||||
MODULE_DESCRIPTION("Avance Logic ALS1X0");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP},"
|
||||
MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");
|
||||
MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
|
||||
"{Avance Logic ALS-007}}"
|
||||
"{{Avance Logic,ALS100 - PRO16PNP},"
|
||||
"{Avance Logic,ALS110},"
|
||||
"{Avance Logic,ALS120},"
|
||||
"{Avance Logic,ALS200},"
|
||||
@@ -45,9 +49,12 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP},"
|
||||
"{Avance Logic,ALS120},"
|
||||
"{RTL,RTL3000}}");
|
||||
|
||||
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
|
||||
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
|
||||
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
|
||||
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
|
||||
@@ -57,14 +64,15 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
|
||||
static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for als100 based soundcard.");
|
||||
MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard.");
|
||||
module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for als100 based soundcard.");
|
||||
MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard.");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable als100 based soundcard.");
|
||||
MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard.");
|
||||
|
||||
MODULE_ALIAS("snd-dt019x");
|
||||
|
||||
struct snd_card_als100 {
|
||||
int dev_no;
|
||||
struct pnp_dev *dev;
|
||||
struct pnp_dev *devmpu;
|
||||
struct pnp_dev *devopl;
|
||||
@@ -72,25 +80,43 @@ struct snd_card_als100 {
|
||||
};
|
||||
|
||||
static struct pnp_card_device_id snd_als100_pnpids[] = {
|
||||
/* DT197A30 */
|
||||
{ .id = "RWB1688",
|
||||
.devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
|
||||
.driver_data = SB_HW_DT019X },
|
||||
/* DT0196 / ALS-007 */
|
||||
{ .id = "ALS0007",
|
||||
.devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
|
||||
.driver_data = SB_HW_DT019X },
|
||||
/* ALS100 - PRO16PNP */
|
||||
{ .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
|
||||
{ .id = "ALS0001",
|
||||
.devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
|
||||
.driver_data = SB_HW_ALS100 },
|
||||
/* ALS110 - MF1000 - Digimate 3D Sound */
|
||||
{ .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } } },
|
||||
{ .id = "ALS0110",
|
||||
.devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } },
|
||||
.driver_data = SB_HW_ALS100 },
|
||||
/* ALS120 */
|
||||
{ .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } },
|
||||
{ .id = "ALS0120",
|
||||
.devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
|
||||
.driver_data = SB_HW_ALS100 },
|
||||
/* ALS200 */
|
||||
{ .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } } },
|
||||
{ .id = "ALS0200",
|
||||
.devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } },
|
||||
.driver_data = SB_HW_ALS100 },
|
||||
/* ALS200 OEM */
|
||||
{ .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } } },
|
||||
{ .id = "ALS0200",
|
||||
.devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } },
|
||||
.driver_data = SB_HW_ALS100 },
|
||||
/* RTL3000 */
|
||||
{ .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } },
|
||||
{ .id = "", } /* end */
|
||||
{ .id = "RTL3000",
|
||||
.devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
|
||||
.driver_data = SB_HW_ALS100 },
|
||||
{ .id = "" } /* end */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids);
|
||||
|
||||
#define DRIVER_NAME "snd-card-als100"
|
||||
|
||||
static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
|
||||
struct pnp_card_link *card,
|
||||
const struct pnp_card_device_id *id)
|
||||
@@ -113,8 +139,12 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
|
||||
return err;
|
||||
}
|
||||
port[dev] = pnp_port_start(pdev, 0);
|
||||
dma8[dev] = pnp_dma(pdev, 1);
|
||||
dma16[dev] = pnp_dma(pdev, 0);
|
||||
if (id->driver_data == SB_HW_DT019X)
|
||||
dma8[dev] = pnp_dma(pdev, 0);
|
||||
else {
|
||||
dma8[dev] = pnp_dma(pdev, 1);
|
||||
dma16[dev] = pnp_dma(pdev, 0);
|
||||
}
|
||||
irq[dev] = pnp_irq(pdev, 0);
|
||||
|
||||
pdev = acard->devmpu;
|
||||
@@ -175,22 +205,33 @@ static int __devinit snd_card_als100_probe(int dev,
|
||||
}
|
||||
snd_card_set_dev(card, &pcard->card->dev);
|
||||
|
||||
if ((error = snd_sbdsp_create(card, port[dev],
|
||||
irq[dev],
|
||||
snd_sb16dsp_interrupt,
|
||||
dma8[dev],
|
||||
dma16[dev],
|
||||
SB_HW_ALS100, &chip)) < 0) {
|
||||
if (pid->driver_data == SB_HW_DT019X)
|
||||
dma16[dev] = -1;
|
||||
|
||||
error = snd_sbdsp_create(card, port[dev], irq[dev],
|
||||
snd_sb16dsp_interrupt,
|
||||
dma8[dev], dma16[dev],
|
||||
pid->driver_data,
|
||||
&chip);
|
||||
if (error < 0) {
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
acard->chip = chip;
|
||||
|
||||
strcpy(card->driver, "ALS100");
|
||||
strcpy(card->shortname, "Avance Logic ALS100");
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
|
||||
card->shortname, chip->name, chip->port,
|
||||
irq[dev], dma8[dev], dma16[dev]);
|
||||
if (pid->driver_data == SB_HW_DT019X) {
|
||||
strcpy(card->driver, "DT-019X");
|
||||
strcpy(card->shortname, "Diamond Tech. DT-019X");
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
|
||||
card->shortname, chip->name, chip->port,
|
||||
irq[dev], dma8[dev]);
|
||||
} else {
|
||||
strcpy(card->driver, "ALS100");
|
||||
strcpy(card->shortname, "Avance Logic ALS100");
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
|
||||
card->shortname, chip->name, chip->port,
|
||||
irq[dev], dma8[dev], dma16[dev]);
|
||||
}
|
||||
|
||||
if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
|
||||
snd_card_free(card);
|
||||
@@ -203,9 +244,19 @@ static int __devinit snd_card_als100_probe(int dev,
|
||||
}
|
||||
|
||||
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
|
||||
if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100,
|
||||
int mpu_type = MPU401_HW_ALS100;
|
||||
|
||||
if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
|
||||
mpu_irq[dev] = -1;
|
||||
|
||||
if (pid->driver_data == SB_HW_DT019X)
|
||||
mpu_type = MPU401_HW_MPU401;
|
||||
|
||||
if (snd_mpu401_uart_new(card, 0,
|
||||
mpu_type,
|
||||
mpu_port[dev], 0,
|
||||
mpu_irq[dev], IRQF_DISABLED,
|
||||
mpu_irq[dev],
|
||||
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
|
||||
NULL) < 0)
|
||||
snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
|
||||
}
|
||||
@@ -291,7 +342,7 @@ static int snd_als100_pnp_resume(struct pnp_card_link *pcard)
|
||||
|
||||
static struct pnp_card_driver als100_pnpc_driver = {
|
||||
.flags = PNP_DRIVER_RES_DISABLE,
|
||||
.name = "als100",
|
||||
.name = "als100",
|
||||
.id_table = snd_als100_pnpids,
|
||||
.probe = snd_als100_pnp_detect,
|
||||
.remove = __devexit_p(snd_als100_pnp_remove),
|
||||
@@ -312,7 +363,7 @@ static int __init alsa_card_als100_init(void)
|
||||
if (!als100_devices) {
|
||||
pnp_unregister_card_driver(&als100_pnpc_driver);
|
||||
#ifdef MODULE
|
||||
snd_printk(KERN_ERR "no ALS100 based soundcards found\n");
|
||||
snd_printk(KERN_ERR "no Avance Logic based soundcards found\n");
|
||||
#endif
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
|
||||
/*
|
||||
dt019x.c - driver for Diamond Technologies DT-0197H based soundcards.
|
||||
Copyright (C) 1999, 2002 by Massimo Piccioni <dafastidio@libero.it>
|
||||
|
||||
Generalised for soundcards based on DT-0196 and ALS-007 chips
|
||||
by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/pnp.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/mpu401.h>
|
||||
#include <sound/opl3.h>
|
||||
#include <sound/sb.h>
|
||||
|
||||
#define PFX "dt019x: "
|
||||
|
||||
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
|
||||
MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
|
||||
"{Avance Logic ALS-007}}");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
||||
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; /* PnP setup */
|
||||
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
|
||||
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
|
||||
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */
|
||||
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */
|
||||
static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard.");
|
||||
module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard.");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard.");
|
||||
|
||||
struct snd_card_dt019x {
|
||||
struct pnp_dev *dev;
|
||||
struct pnp_dev *devmpu;
|
||||
struct pnp_dev *devopl;
|
||||
struct snd_sb *chip;
|
||||
};
|
||||
|
||||
static struct pnp_card_device_id snd_dt019x_pnpids[] = {
|
||||
/* DT197A30 */
|
||||
{ .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
|
||||
/* DT0196 / ALS-007 */
|
||||
{ .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
|
||||
{ .id = "", }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids);
|
||||
|
||||
|
||||
#define DRIVER_NAME "snd-card-dt019x"
|
||||
|
||||
|
||||
static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard,
|
||||
struct pnp_card_link *card,
|
||||
const struct pnp_card_device_id *pid)
|
||||
{
|
||||
struct pnp_dev *pdev;
|
||||
int err;
|
||||
|
||||
acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
|
||||
if (acard->dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
|
||||
acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL);
|
||||
|
||||
pdev = acard->dev;
|
||||
|
||||
err = pnp_activate_dev(pdev);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
port[dev] = pnp_port_start(pdev, 0);
|
||||
dma8[dev] = pnp_dma(pdev, 0);
|
||||
irq[dev] = pnp_irq(pdev, 0);
|
||||
snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n",
|
||||
port[dev],irq[dev],dma8[dev]);
|
||||
|
||||
pdev = acard->devmpu;
|
||||
if (pdev != NULL) {
|
||||
err = pnp_activate_dev(pdev);
|
||||
if (err < 0) {
|
||||
pnp_release_card_device(pdev);
|
||||
snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n");
|
||||
goto __mpu_error;
|
||||
}
|
||||
mpu_port[dev] = pnp_port_start(pdev, 0);
|
||||
mpu_irq[dev] = pnp_irq(pdev, 0);
|
||||
snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n",
|
||||
mpu_port[dev],mpu_irq[dev]);
|
||||
} else {
|
||||
__mpu_error:
|
||||
acard->devmpu = NULL;
|
||||
mpu_port[dev] = -1;
|
||||
}
|
||||
|
||||
pdev = acard->devopl;
|
||||
if (pdev != NULL) {
|
||||
err = pnp_activate_dev(pdev);
|
||||
if (err < 0) {
|
||||
pnp_release_card_device(pdev);
|
||||
snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n");
|
||||
goto __fm_error;
|
||||
}
|
||||
fm_port[dev] = pnp_port_start(pdev, 0);
|
||||
snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]);
|
||||
} else {
|
||||
__fm_error:
|
||||
acard->devopl = NULL;
|
||||
fm_port[dev] = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid)
|
||||
{
|
||||
int error;
|
||||
struct snd_sb *chip;
|
||||
struct snd_card *card;
|
||||
struct snd_card_dt019x *acard;
|
||||
struct snd_opl3 *opl3;
|
||||
|
||||
error = snd_card_create(index[dev], id[dev], THIS_MODULE,
|
||||
sizeof(struct snd_card_dt019x), &card);
|
||||
if (error < 0)
|
||||
return error;
|
||||
acard = card->private_data;
|
||||
|
||||
snd_card_set_dev(card, &pcard->card->dev);
|
||||
if ((error = snd_card_dt019x_pnp(dev, acard, pcard, pid))) {
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
|
||||
if ((error = snd_sbdsp_create(card, port[dev],
|
||||
irq[dev],
|
||||
snd_sb16dsp_interrupt,
|
||||
dma8[dev],
|
||||
-1,
|
||||
SB_HW_DT019X,
|
||||
&chip)) < 0) {
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
acard->chip = chip;
|
||||
|
||||
strcpy(card->driver, "DT-019X");
|
||||
strcpy(card->shortname, "Diamond Tech. DT-019X");
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
|
||||
card->shortname, chip->name, chip->port,
|
||||
irq[dev], dma8[dev]);
|
||||
|
||||
if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
if ((error = snd_sbmixer_new(chip)) < 0) {
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
|
||||
if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
|
||||
mpu_irq[dev] = -1;
|
||||
if (snd_mpu401_uart_new(card, 0,
|
||||
/* MPU401_HW_SB,*/
|
||||
MPU401_HW_MPU401,
|
||||
mpu_port[dev], 0,
|
||||
mpu_irq[dev],
|
||||
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
|
||||
NULL) < 0)
|
||||
snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]);
|
||||
}
|
||||
|
||||
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
|
||||
if (snd_opl3_create(card,
|
||||
fm_port[dev],
|
||||
fm_port[dev] + 2,
|
||||
OPL3_HW_AUTO, 0, &opl3) < 0) {
|
||||
snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n",
|
||||
fm_port[dev], fm_port[dev] + 2);
|
||||
} else {
|
||||
if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = snd_card_register(card)) < 0) {
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
pnp_set_card_drvdata(pcard, card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int __devinitdata dt019x_devices;
|
||||
|
||||
static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card,
|
||||
const struct pnp_card_device_id *pid)
|
||||
{
|
||||
static int dev;
|
||||
int res;
|
||||
|
||||
for ( ; dev < SNDRV_CARDS; dev++) {
|
||||
if (!enable[dev])
|
||||
continue;
|
||||
res = snd_card_dt019x_probe(dev, card, pid);
|
||||
if (res < 0)
|
||||
return res;
|
||||
dev++;
|
||||
dt019x_devices++;
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard)
|
||||
{
|
||||
snd_card_free(pnp_get_card_drvdata(pcard));
|
||||
pnp_set_card_drvdata(pcard, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int snd_dt019x_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
|
||||
{
|
||||
struct snd_card *card = pnp_get_card_drvdata(pcard);
|
||||
struct snd_card_dt019x *acard = card->private_data;
|
||||
struct snd_sb *chip = acard->chip;
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
snd_pcm_suspend_all(chip->pcm);
|
||||
snd_sbmixer_suspend(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_dt019x_pnp_resume(struct pnp_card_link *pcard)
|
||||
{
|
||||
struct snd_card *card = pnp_get_card_drvdata(pcard);
|
||||
struct snd_card_dt019x *acard = card->private_data;
|
||||
struct snd_sb *chip = acard->chip;
|
||||
|
||||
snd_sbdsp_reset(chip);
|
||||
snd_sbmixer_resume(chip);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct pnp_card_driver dt019x_pnpc_driver = {
|
||||
.flags = PNP_DRIVER_RES_DISABLE,
|
||||
.name = "dt019x",
|
||||
.id_table = snd_dt019x_pnpids,
|
||||
.probe = snd_dt019x_pnp_probe,
|
||||
.remove = __devexit_p(snd_dt019x_pnp_remove),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = snd_dt019x_pnp_suspend,
|
||||
.resume = snd_dt019x_pnp_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init alsa_card_dt019x_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pnp_register_card_driver(&dt019x_pnpc_driver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!dt019x_devices) {
|
||||
pnp_unregister_card_driver(&dt019x_pnpc_driver);
|
||||
#ifdef MODULE
|
||||
snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n");
|
||||
#endif
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit alsa_card_dt019x_exit(void)
|
||||
{
|
||||
pnp_unregister_card_driver(&dt019x_pnpc_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_dt019x_init)
|
||||
module_exit(alsa_card_dt019x_exit)
|
||||
@@ -1558,7 +1558,7 @@ static int __devinit snd_card_miro_pnp(struct snd_miro *chip,
|
||||
|
||||
err = pnp_activate_dev(devmc);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n",
|
||||
snd_printk(KERN_ERR "MC pnp configure failure: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/dma.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/wss.h>
|
||||
#include <sound/mpu401.h>
|
||||
#include <sound/opl3.h>
|
||||
@@ -143,12 +144,8 @@ struct snd_opti9xx {
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
long wss_base;
|
||||
int irq;
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
struct pnp_dev *dev;
|
||||
struct pnp_dev *devmpu;
|
||||
#endif /* CONFIG_PNP */
|
||||
};
|
||||
|
||||
static int snd_opti9xx_pnp_is_probed;
|
||||
@@ -158,12 +155,17 @@ static int snd_opti9xx_pnp_is_probed;
|
||||
static struct pnp_card_device_id snd_opti9xx_pnpids[] = {
|
||||
#ifndef OPTi93X
|
||||
/* OPTi 82C924 */
|
||||
{ .id = "OPT0924", .devs = { { "OPT0000" }, { "OPT0002" } }, .driver_data = 0x0924 },
|
||||
{ .id = "OPT0924",
|
||||
.devs = { { "OPT0000" }, { "OPT0002" }, { "OPT0005" } },
|
||||
.driver_data = 0x0924 },
|
||||
/* OPTi 82C925 */
|
||||
{ .id = "OPT0925", .devs = { { "OPT9250" }, { "OPT0002" } }, .driver_data = 0x0925 },
|
||||
{ .id = "OPT0925",
|
||||
.devs = { { "OPT9250" }, { "OPT0002" }, { "OPT0005" } },
|
||||
.driver_data = 0x0925 },
|
||||
#else
|
||||
/* OPTi 82C931/3 */
|
||||
{ .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } }, .driver_data = 0x0931 },
|
||||
{ .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } },
|
||||
.driver_data = 0x0931 },
|
||||
#endif /* OPTi93X */
|
||||
{ .id = "" }
|
||||
};
|
||||
@@ -206,24 +208,35 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
|
||||
chip->hardware = hardware;
|
||||
strcpy(chip->name, snd_opti9xx_names[hardware]);
|
||||
|
||||
chip->mc_base_size = opti9xx_mc_size[hardware];
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
|
||||
chip->irq = -1;
|
||||
|
||||
#ifndef OPTi93X
|
||||
#ifdef CONFIG_PNP
|
||||
if (isapnp && chip->mc_base)
|
||||
/* PnP resource gives the least 10 bits */
|
||||
chip->mc_base |= 0xc00;
|
||||
else
|
||||
#endif /* CONFIG_PNP */
|
||||
{
|
||||
chip->mc_base = 0xf8c;
|
||||
chip->mc_base_size = opti9xx_mc_size[hardware];
|
||||
}
|
||||
#else
|
||||
chip->mc_base_size = opti9xx_mc_size[hardware];
|
||||
#endif
|
||||
|
||||
switch (hardware) {
|
||||
#ifndef OPTi93X
|
||||
case OPTi9XX_HW_82C928:
|
||||
case OPTi9XX_HW_82C929:
|
||||
chip->mc_base = 0xf8c;
|
||||
chip->password = (hardware == OPTi9XX_HW_82C928) ? 0xe2 : 0xe3;
|
||||
chip->pwd_reg = 3;
|
||||
break;
|
||||
|
||||
case OPTi9XX_HW_82C924:
|
||||
case OPTi9XX_HW_82C925:
|
||||
chip->mc_base = 0xf8c;
|
||||
chip->password = 0xe5;
|
||||
chip->pwd_reg = 3;
|
||||
break;
|
||||
@@ -291,7 +304,7 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
|
||||
unsigned char value)
|
||||
{
|
||||
@@ -340,7 +353,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
|
||||
|
||||
|
||||
static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
|
||||
long wss_base,
|
||||
long port,
|
||||
int irq, int dma1, int dma2,
|
||||
long mpu_port, int mpu_irq)
|
||||
{
|
||||
@@ -353,16 +366,23 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
|
||||
switch (chip->hardware) {
|
||||
#ifndef OPTi93X
|
||||
case OPTi9XX_HW_82C924:
|
||||
/* opti 929 mode (?), OPL3 clock output, audio enable */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0xf0, 0xfc);
|
||||
/* enable wave audio */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
|
||||
|
||||
case OPTi9XX_HW_82C925:
|
||||
/* enable WSS mode */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
|
||||
/* OPL3 FM synthesis */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20);
|
||||
/* disable Sound Blaster IRQ and DMA */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
|
||||
#ifdef CS4231
|
||||
/* cs4231/4248 fix enabled */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
|
||||
#else
|
||||
/* cs4231/4248 fix disabled */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02);
|
||||
#endif /* CS4231 */
|
||||
break;
|
||||
@@ -410,21 +430,26 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (wss_base) {
|
||||
case 0x530:
|
||||
/* PnP resource says it decodes only 10 bits of address */
|
||||
switch (port & 0x3ff) {
|
||||
case 0x130:
|
||||
chip->wss_base = 0x530;
|
||||
wss_base_bits = 0x00;
|
||||
break;
|
||||
case 0x604:
|
||||
case 0x204:
|
||||
chip->wss_base = 0x604;
|
||||
wss_base_bits = 0x03;
|
||||
break;
|
||||
case 0xe80:
|
||||
case 0x280:
|
||||
chip->wss_base = 0xe80;
|
||||
wss_base_bits = 0x01;
|
||||
break;
|
||||
case 0xf40:
|
||||
case 0x340:
|
||||
chip->wss_base = 0xf40;
|
||||
wss_base_bits = 0x02;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base);
|
||||
snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", port);
|
||||
goto __skip_base;
|
||||
}
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
|
||||
@@ -486,7 +511,7 @@ __skip_base:
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
#ifndef OPTi93X
|
||||
outb(irq_bits << 3 | dma_bits, wss_base);
|
||||
outb(irq_bits << 3 | dma_bits, chip->wss_base);
|
||||
#else /* OPTi93X */
|
||||
snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
|
||||
#endif /* OPTi93X */
|
||||
@@ -546,6 +571,93 @@ __skip_mpu:
|
||||
|
||||
#ifdef OPTi93X
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_opti93x_controls[] = {
|
||||
WSS_DOUBLE("Master Playback Switch", 0,
|
||||
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE_TLV("Master Playback Volume", 0,
|
||||
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
|
||||
db_scale_5bit_3db_step),
|
||||
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit),
|
||||
WSS_DOUBLE_TLV("FM Playback Volume", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1,
|
||||
db_scale_4bit_12db_max),
|
||||
WSS_DOUBLE("Line Playback Switch", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
|
||||
WSS_DOUBLE_TLV("Line Playback Volume", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1,
|
||||
db_scale_4bit_12db_max),
|
||||
WSS_DOUBLE("Mic Playback Switch", 0,
|
||||
OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE_TLV("Mic Playback Volume", 0,
|
||||
OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1,
|
||||
db_scale_4bit_12db_max),
|
||||
WSS_DOUBLE_TLV("CD Playback Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1,
|
||||
db_scale_4bit_12db_max),
|
||||
WSS_DOUBLE("Aux Playback Switch", 0,
|
||||
OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE_TLV("Aux Playback Volume", 0,
|
||||
OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1,
|
||||
db_scale_4bit_12db_max),
|
||||
};
|
||||
|
||||
static int __devinit snd_opti93x_mixer(struct snd_wss *chip)
|
||||
{
|
||||
struct snd_card *card;
|
||||
unsigned int idx;
|
||||
struct snd_ctl_elem_id id1, id2;
|
||||
int err;
|
||||
|
||||
if (snd_BUG_ON(!chip || !chip->pcm))
|
||||
return -EINVAL;
|
||||
|
||||
card = chip->card;
|
||||
|
||||
strcpy(card->mixername, chip->pcm->name);
|
||||
|
||||
memset(&id1, 0, sizeof(id1));
|
||||
memset(&id2, 0, sizeof(id2));
|
||||
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
/* reassign AUX0 switch to CD */
|
||||
strcpy(id1.name, "Aux Playback Switch");
|
||||
strcpy(id2.name, "CD Playback Switch");
|
||||
err = snd_ctl_rename_id(card, &id1, &id2);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "Cannot rename opti93x control\n");
|
||||
return err;
|
||||
}
|
||||
/* reassign AUX1 switch to FM */
|
||||
strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
|
||||
strcpy(id2.name, "FM Playback Switch");
|
||||
err = snd_ctl_rename_id(card, &id1, &id2);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "Cannot rename opti93x control\n");
|
||||
return err;
|
||||
}
|
||||
/* remove AUX1 volume */
|
||||
strcpy(id1.name, "Aux Playback Volume"); id1.index = 1;
|
||||
snd_ctl_remove_id(card, &id1);
|
||||
|
||||
/* Replace WSS volume controls with OPTi93x volume controls */
|
||||
id1.index = 0;
|
||||
for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
|
||||
strcpy(id1.name, snd_opti93x_controls[idx].name);
|
||||
snd_ctl_remove_id(card, &id1);
|
||||
|
||||
err = snd_ctl_add(card,
|
||||
snd_ctl_new1(&snd_opti93x_controls[idx], chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct snd_opti9xx *chip = dev_id;
|
||||
@@ -641,15 +753,15 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
|
||||
{
|
||||
struct pnp_dev *pdev;
|
||||
int err;
|
||||
struct pnp_dev *devmpu;
|
||||
#ifndef OPTi93X
|
||||
struct pnp_dev *devmc;
|
||||
#endif
|
||||
|
||||
chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
|
||||
if (chip->dev == NULL)
|
||||
pdev = pnp_request_card_device(card, pid->devs[0].id, NULL);
|
||||
if (pdev == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
|
||||
|
||||
pdev = chip->dev;
|
||||
|
||||
err = pnp_activate_dev(pdev);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
|
||||
@@ -662,9 +774,24 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
|
||||
chip->mc_indir_index = pnp_port_start(pdev, 3) + 2;
|
||||
chip->mc_indir_size = pnp_port_len(pdev, 3) - 2;
|
||||
#else
|
||||
if (pid->driver_data != 0x0924)
|
||||
port = pnp_port_start(pdev, 1);
|
||||
devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
|
||||
if (devmc == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
err = pnp_activate_dev(devmc);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "MC pnp configure failure: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
port = pnp_port_start(pdev, 1);
|
||||
fm_port = pnp_port_start(pdev, 2) + 8;
|
||||
/*
|
||||
* The MC(0) is never accessed and card does not
|
||||
* include it in the PnP resource range. OPTI93x include it.
|
||||
*/
|
||||
chip->mc_base = pnp_port_start(devmc, 0) - 1;
|
||||
chip->mc_base_size = pnp_port_len(devmc, 0) + 1;
|
||||
#endif /* OPTi93X */
|
||||
irq = pnp_irq(pdev, 0);
|
||||
dma1 = pnp_dma(pdev, 0);
|
||||
@@ -672,16 +799,16 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
|
||||
dma2 = pnp_dma(pdev, 1);
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
pdev = chip->devmpu;
|
||||
if (pdev && mpu_port > 0) {
|
||||
err = pnp_activate_dev(pdev);
|
||||
devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
|
||||
|
||||
if (devmpu && mpu_port > 0) {
|
||||
err = pnp_activate_dev(devmpu);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "AUDIO pnp configure failure\n");
|
||||
snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
|
||||
mpu_port = -1;
|
||||
chip->devmpu = NULL;
|
||||
} else {
|
||||
mpu_port = pnp_port_start(pdev, 0);
|
||||
mpu_irq = pnp_irq(pdev, 0);
|
||||
mpu_port = pnp_port_start(devmpu, 0);
|
||||
mpu_irq = pnp_irq(devmpu, 0);
|
||||
}
|
||||
}
|
||||
return pid->driver_data;
|
||||
@@ -736,7 +863,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2,
|
||||
error = snd_wss_create(card, chip->wss_base + 4, -1, irq, dma1, xdma2,
|
||||
#ifdef OPTi93X
|
||||
WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
|
||||
#else
|
||||
@@ -754,6 +881,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
error = snd_wss_mixer(codec);
|
||||
if (error < 0)
|
||||
return error;
|
||||
#ifdef OPTi93X
|
||||
error = snd_opti93x_mixer(codec);
|
||||
if (error < 0)
|
||||
return error;
|
||||
#endif
|
||||
#ifdef CS4231
|
||||
error = snd_wss_timer(codec, 0, &timer);
|
||||
if (error < 0)
|
||||
@@ -772,10 +904,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
sprintf(card->shortname, "OPTi %s", card->driver);
|
||||
#if defined(CS4231) || defined(OPTi93X)
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
|
||||
card->shortname, pcm->name, port + 4, irq, dma1, xdma2);
|
||||
card->shortname, pcm->name,
|
||||
chip->wss_base + 4, irq, dma1, xdma2);
|
||||
#else
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
|
||||
card->shortname, pcm->name, port + 4, irq, dma1);
|
||||
card->shortname, pcm->name, chip->wss_base + 4, irq, dma1);
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
|
||||
@@ -969,9 +1102,6 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
|
||||
snd_card_free(card);
|
||||
return error;
|
||||
}
|
||||
if (hw <= OPTi9XX_HW_82C930)
|
||||
chip->mc_base -= 0x80;
|
||||
|
||||
error = snd_opti9xx_read_check(chip);
|
||||
if (error) {
|
||||
snd_printk(KERN_ERR "OPTI chip not found\n");
|
||||
|
||||
@@ -12,6 +12,7 @@ snd-sb16-objs := sb16.o
|
||||
snd-sbawe-objs := sbawe.o emu8000.o
|
||||
snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
|
||||
snd-es968-objs := es968.o
|
||||
snd-jazz16-objs := jazz16.o
|
||||
|
||||
# Toplevel Module Dependency
|
||||
obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
|
||||
@@ -21,6 +22,7 @@ obj-$(CONFIG_SND_SB8) += snd-sb8.o
|
||||
obj-$(CONFIG_SND_SB16) += snd-sb16.o
|
||||
obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
|
||||
obj-$(CONFIG_SND_ES968) += snd-es968.o
|
||||
obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o
|
||||
ifeq ($(CONFIG_SND_SB16_CSP),y)
|
||||
obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
|
||||
obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
|
||||
/*
|
||||
* jazz16.c - driver for Media Vision Jazz16 based soundcards.
|
||||
* Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
|
||||
* Based on patches posted by Rask Ingemann Lambertsen and Rene Herman.
|
||||
* Based on OSS Sound Blaster driver.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/dma.h>
|
||||
#include <linux/isa.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/mpu401.h>
|
||||
#include <sound/opl3.h>
|
||||
#include <sound/sb.h>
|
||||
#define SNDRV_LEGACY_FIND_FREE_IRQ
|
||||
#define SNDRV_LEGACY_FIND_FREE_DMA
|
||||
#include <sound/initval.h>
|
||||
|
||||
#define PFX "jazz16: "
|
||||
|
||||
MODULE_DESCRIPTION("Media Vision Jazz16");
|
||||
MODULE_SUPPORTED_DEVICE("{{Media Vision ??? },"
|
||||
"{RTL,RTL3000}}");
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
|
||||
static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
|
||||
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
|
||||
static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
|
||||
static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard.");
|
||||
module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard.");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard.");
|
||||
module_param_array(port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(port, "Port # for jazz16 driver.");
|
||||
module_param_array(mpu_port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver.");
|
||||
module_param_array(irq, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver.");
|
||||
module_param_array(mpu_irq, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver.");
|
||||
module_param_array(dma8, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver.");
|
||||
module_param_array(dma16, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver.");
|
||||
|
||||
#define SB_JAZZ16_WAKEUP 0xaf
|
||||
#define SB_JAZZ16_SET_PORTS 0x50
|
||||
#define SB_DSP_GET_JAZZ_BRD_REV 0xfa
|
||||
#define SB_JAZZ16_SET_DMAINTR 0xfb
|
||||
#define SB_DSP_GET_JAZZ_MODEL 0xfe
|
||||
|
||||
struct snd_card_jazz16 {
|
||||
struct snd_sb *chip;
|
||||
};
|
||||
|
||||
static irqreturn_t jazz16_interrupt(int irq, void *chip)
|
||||
{
|
||||
return snd_sb8dsp_interrupt(chip);
|
||||
}
|
||||
|
||||
static int __devinit jazz16_configure_ports(unsigned long port,
|
||||
unsigned long mpu_port, int idx)
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
if (!request_region(0x201, 1, "jazz16 config")) {
|
||||
snd_printk(KERN_ERR "config port region is already in use.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
outb(SB_JAZZ16_WAKEUP - idx, 0x201);
|
||||
udelay(100);
|
||||
outb(SB_JAZZ16_SET_PORTS + idx, 0x201);
|
||||
udelay(100);
|
||||
val = port & 0x70;
|
||||
val |= (mpu_port & 0x30) >> 4;
|
||||
outb(val, 0x201);
|
||||
|
||||
release_region(0x201, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit jazz16_detect_board(unsigned long port,
|
||||
unsigned long mpu_port)
|
||||
{
|
||||
int err;
|
||||
int val;
|
||||
struct snd_sb chip;
|
||||
|
||||
if (!request_region(port, 0x10, "jazz16")) {
|
||||
snd_printk(KERN_ERR "I/O port region is already in use.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
/* just to call snd_sbdsp_command/reset/get_byte() */
|
||||
chip.port = port;
|
||||
|
||||
err = snd_sbdsp_reset(&chip);
|
||||
if (err < 0)
|
||||
for (val = 0; val < 4; val++) {
|
||||
err = jazz16_configure_ports(port, mpu_port, val);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
err = snd_sbdsp_reset(&chip);
|
||||
if (!err)
|
||||
break;
|
||||
}
|
||||
if (err < 0) {
|
||||
err = -ENODEV;
|
||||
goto err_unmap;
|
||||
}
|
||||
if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) {
|
||||
err = -EBUSY;
|
||||
goto err_unmap;
|
||||
}
|
||||
val = snd_sbdsp_get_byte(&chip);
|
||||
if (val >= 0x30)
|
||||
snd_sbdsp_get_byte(&chip);
|
||||
|
||||
if ((val & 0xf0) != 0x10) {
|
||||
err = -ENODEV;
|
||||
goto err_unmap;
|
||||
}
|
||||
if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) {
|
||||
err = -EBUSY;
|
||||
goto err_unmap;
|
||||
}
|
||||
snd_sbdsp_get_byte(&chip);
|
||||
err = snd_sbdsp_get_byte(&chip);
|
||||
snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n",
|
||||
val, err);
|
||||
|
||||
err = 0;
|
||||
|
||||
err_unmap:
|
||||
release_region(port, 0x10);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq)
|
||||
{
|
||||
static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4,
|
||||
0, 2, 5, 0, 0, 0, 0, 6 };
|
||||
static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 };
|
||||
|
||||
if (jazz_dma_bits[chip->dma8] == 0 ||
|
||||
jazz_dma_bits[chip->dma16] == 0 ||
|
||||
jazz_irq_bits[chip->irq] == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR))
|
||||
return -EBUSY;
|
||||
|
||||
if (!snd_sbdsp_command(chip,
|
||||
jazz_dma_bits[chip->dma8] |
|
||||
(jazz_dma_bits[chip->dma16] << 4)))
|
||||
return -EBUSY;
|
||||
|
||||
if (!snd_sbdsp_command(chip,
|
||||
jazz_irq_bits[chip->irq] |
|
||||
(jazz_irq_bits[mpu_irq] << 4)))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
if (!enable[dev])
|
||||
return 0;
|
||||
if (port[dev] == SNDRV_AUTO_PORT) {
|
||||
snd_printk(KERN_ERR "please specify port\n");
|
||||
return 0;
|
||||
} else if (port[dev] == 0x200 || (port[dev] & ~0x270)) {
|
||||
snd_printk(KERN_ERR "incorrect port specified\n");
|
||||
return 0;
|
||||
}
|
||||
if (dma8[dev] != SNDRV_AUTO_DMA &&
|
||||
dma8[dev] != 1 && dma8[dev] != 3) {
|
||||
snd_printk(KERN_ERR "dma8 must be 1 or 3\n");
|
||||
return 0;
|
||||
}
|
||||
if (dma16[dev] != SNDRV_AUTO_DMA &&
|
||||
dma16[dev] != 5 && dma16[dev] != 7) {
|
||||
snd_printk(KERN_ERR "dma16 must be 5 or 7\n");
|
||||
return 0;
|
||||
}
|
||||
if (mpu_port[dev] != SNDRV_AUTO_PORT &&
|
||||
(mpu_port[dev] & ~0x030) != 0x300) {
|
||||
snd_printk(KERN_ERR "incorrect mpu_port specified\n");
|
||||
return 0;
|
||||
}
|
||||
if (mpu_irq[dev] != SNDRV_AUTO_DMA &&
|
||||
mpu_irq[dev] != 2 && mpu_irq[dev] != 3 &&
|
||||
mpu_irq[dev] != 5 && mpu_irq[dev] != 7) {
|
||||
snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
struct snd_card *card;
|
||||
struct snd_card_jazz16 *jazz16;
|
||||
struct snd_sb *chip;
|
||||
struct snd_opl3 *opl3;
|
||||
static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1};
|
||||
static int possible_dmas8[] = {1, 3, -1};
|
||||
static int possible_dmas16[] = {5, 7, -1};
|
||||
int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq;
|
||||
|
||||
err = snd_card_create(index[dev], id[dev], THIS_MODULE,
|
||||
sizeof(struct snd_card_jazz16), &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
jazz16 = card->private_data;
|
||||
|
||||
xirq = irq[dev];
|
||||
if (xirq == SNDRV_AUTO_IRQ) {
|
||||
xirq = snd_legacy_find_free_irq(possible_irqs);
|
||||
if (xirq < 0) {
|
||||
snd_printk(KERN_ERR "unable to find a free IRQ\n");
|
||||
err = -EBUSY;
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
xdma8 = dma8[dev];
|
||||
if (xdma8 == SNDRV_AUTO_DMA) {
|
||||
xdma8 = snd_legacy_find_free_dma(possible_dmas8);
|
||||
if (xdma8 < 0) {
|
||||
snd_printk(KERN_ERR "unable to find a free DMA8\n");
|
||||
err = -EBUSY;
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
xdma16 = dma16[dev];
|
||||
if (xdma16 == SNDRV_AUTO_DMA) {
|
||||
xdma16 = snd_legacy_find_free_dma(possible_dmas16);
|
||||
if (xdma16 < 0) {
|
||||
snd_printk(KERN_ERR "unable to find a free DMA16\n");
|
||||
err = -EBUSY;
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
|
||||
xmpu_port = mpu_port[dev];
|
||||
if (xmpu_port == SNDRV_AUTO_PORT)
|
||||
xmpu_port = 0;
|
||||
err = jazz16_detect_board(port[dev], xmpu_port);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "Media Vision Jazz16 board not detected\n");
|
||||
goto err_free;
|
||||
}
|
||||
err = snd_sbdsp_create(card, port[dev], irq[dev],
|
||||
jazz16_interrupt,
|
||||
dma8[dev], dma16[dev],
|
||||
SB_HW_JAZZ16,
|
||||
&chip);
|
||||
if (err < 0)
|
||||
goto err_free;
|
||||
|
||||
xmpu_irq = mpu_irq[dev];
|
||||
if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT)
|
||||
xmpu_irq = 0;
|
||||
err = jazz16_configure_board(chip, xmpu_irq);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "Media Vision Jazz16 configuration failed\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
jazz16->chip = chip;
|
||||
|
||||
strcpy(card->driver, "jazz16");
|
||||
strcpy(card->shortname, "Media Vision Jazz16");
|
||||
sprintf(card->longname,
|
||||
"Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
|
||||
port[dev], xirq, xdma8, xdma16);
|
||||
|
||||
err = snd_sb8dsp_pcm(chip, 0, NULL);
|
||||
if (err < 0)
|
||||
goto err_free;
|
||||
err = snd_sbmixer_new(chip);
|
||||
if (err < 0)
|
||||
goto err_free;
|
||||
|
||||
err = snd_opl3_create(card, chip->port, chip->port + 2,
|
||||
OPL3_HW_AUTO, 1, &opl3);
|
||||
if (err < 0)
|
||||
snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
|
||||
chip->port, chip->port + 2);
|
||||
else {
|
||||
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
|
||||
if (err < 0)
|
||||
goto err_free;
|
||||
}
|
||||
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
|
||||
if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
|
||||
mpu_irq[dev] = -1;
|
||||
|
||||
if (snd_mpu401_uart_new(card, 0,
|
||||
MPU401_HW_MPU401,
|
||||
mpu_port[dev], 0,
|
||||
mpu_irq[dev],
|
||||
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
|
||||
NULL) < 0)
|
||||
snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n",
|
||||
mpu_port[dev]);
|
||||
}
|
||||
|
||||
snd_card_set_dev(card, devptr);
|
||||
|
||||
err = snd_card_register(card);
|
||||
if (err < 0)
|
||||
goto err_free;
|
||||
|
||||
dev_set_drvdata(devptr, card);
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(devptr);
|
||||
|
||||
dev_set_drvdata(devptr, NULL);
|
||||
snd_card_free(card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int snd_jazz16_suspend(struct device *pdev, unsigned int n,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(pdev);
|
||||
struct snd_card_jazz16 *acard = card->private_data;
|
||||
struct snd_sb *chip = acard->chip;
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
snd_pcm_suspend_all(chip->pcm);
|
||||
snd_sbmixer_suspend(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_jazz16_resume(struct device *pdev, unsigned int n)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(pdev);
|
||||
struct snd_card_jazz16 *acard = card->private_data;
|
||||
struct snd_sb *chip = acard->chip;
|
||||
|
||||
snd_sbdsp_reset(chip);
|
||||
snd_sbmixer_resume(chip);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct isa_driver snd_jazz16_driver = {
|
||||
.match = snd_jazz16_match,
|
||||
.probe = snd_jazz16_probe,
|
||||
.remove = __devexit_p(snd_jazz16_remove),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = snd_jazz16_suspend,
|
||||
.resume = snd_jazz16_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = "jazz16"
|
||||
},
|
||||
};
|
||||
|
||||
static int __init alsa_card_jazz16_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_jazz16_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_jazz16_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_jazz16_init)
|
||||
module_exit(alsa_card_jazz16_exit)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user