Commit 1ae204fd authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA update

  - added documentation for OSS emulation
  - CMI8330 - duplex/mixer cleanups
  - via82xx - rewritten for 8233+ (multiple playback, S/PDIF, secondary capture)
  - USB - quirk code update
parent b8038484
......@@ -4539,28 +4539,13 @@
<programlisting>
<![CDATA[
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
/* get the physical page pointer on the given offset */
static struct page *mychip_page(snd_pcm_substream_t *subs,
static struct page *mychip_page(snd_pcm_substream_t *substream,
unsigned long offset)
{
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
unsigned long lpage;
void *pageptr = subs->runtime->dma_area + offset;
struct page *page = NOPAGE_SIGBUS;
lpage = VMALLOC_VMADDR(pageptr);
spin_lock(&init_mm.page_table_lock);
pgd = pgd_offset(&init_mm, lpage);
pmd = pmd_offset(pgd, lpage);
pte = pte_offset(pmd, lpage);
page = pte_page(*pte);
spin_unlock(&init_mm.page_table_lock);
return page;
void *pageptr = substream->runtime->dma_area + offset;
return vmalloc_to_page(pageptr);
}
]]>
</programlisting>
......
NOTES ON KERNEL OSS-EMULATION
=============================
Jan. 9, 2003 Takashi Iwai <tiwai@suse.de>
Modules
=======
ALSA provides a powerful OSS emulation on the kernel.
The OSS emulation for PCM, mixer and sequencer devices is implemented
as add-on kernel modules, snd-pcm-oss, snd-mixer-oss and snd-seq-oss.
When you need to access the OSS PCM, mixer or sequencer devices, the
corresponding module has to be loaded.
For loading these modules automatically, define the aliases in
/etc/modules.conf like below:
alias sound-service-0-0 snd-mixer-oss
alias sound-service-0-1 snd-seq-oss
alias sound-service-0-3 snd-pcm-oss
alias sound-service-0-8 snd-seq-oss
alias sound-service-0-12 snd-pcm-oss
Then the access to an OSS device file such as /dev/dsp0 triggers to
load the necessary module via KMOD.
For auto-loading the secondary card device like /dev/dsp1, the
following aliases are necessary in addition:
alias sound-service-1-0 snd-mixer-oss
alias sound-service-1-3 snd-pcm-oss
alias sound-service-1-12 snd-pcm-oss
Here you don't need to define service-1-1 and service-1-8 because
there is only one sequencer device.
Similarly, you can add definitions for the third or later cards as
sound-service-X-Y.
The OSS-MIDI is emulated directly in the ALSA rawmidi module,
therefore no extra module exists for that purpose.
The currently available OSS configuration is shown in
/proc/asound/oss/sndstat. This shows in the same syntax of
/dev/sndstat, which is available on the commercial OSS driver.
On ALSA, you can symlink /dev/sndstat to this proc file.
Please note that the devices listed in this proc file appear only
after the corresponding OSS-emulation module is loaded. Don't worry
even if "NOT ENABLED IN CONFIG" is shown in it.
Device Mapping
==============
ALSA supports the following OSS device files:
PCM:
/dev/dspX
/dev/adspX
Mixer:
/dev/mixerX
MIDI:
/dev/midi0X
/dev/amidi0X
Sequencer:
/dev/sequencer
/dev/sequencer2 (aka /dev/music)
where X is the card number from 0 to 7.
(NOTE: Some distributions have the device files like /dev/midi0 and
/dev/midi1. They are NOT for OSS but for tclmidi, which is
a totally different thing.)
Unlike the real OSS, ALSA cannot use the device files more than the
assigned ones. For example, the first card cannot use /dev/dsp1 or
/dev/dsp2, but only /dev/dsp0 and /dev/adsp0.
As seen above, PCM and MIDI may have two devices. Usually, the first
PCM device (hw:0,0 in ALSA) is mapped to /dev/dsp and the secondary
device (hw:0,1) to /dev/adsp (if available). For MIDI, /dev/midi and
/dev/amidi, respectively.
You can change this device mapping via the module options of
snd-pcm-oss and snd-rawmidi. In the case of PCM, the following
options are available for snd-pcm-oss:
dsp_map PCM device number assigned to /dev/dspX
(default = 0)
adsp_map PCM device number assigned to /dev/adspX
(default = 1)
For example, to map the third PCM device (hw:0,2) to /dev/adsp0,
define like this:
options snd-pcm-oss adsp_map=2
The options take arrays. For configuring the second card, specify
two entries separated by comma. For example, to map the third PCM
device on the second card to /dev/adsp1, define like below:
options snd-pcm-oss adsp_map=0,2
To change the mapping of MIDI devices, the following options are
available for snd-rawmidi:
midi_map MIDI device number assigned to /dev/midi0X
(default = 0)
amidi_map MIDI device number assigned to /dev/amidi0X
(default = 1)
For example, to assign the third MIDI device on the first card to
/dev/midi00, define as follows:
options snd-rawmidi midi_map=2
PCM Mode
========
As default, ALSA emulates the OSS PCM with so-called plugin layer,
i.e. tries to convert the sample format, rate or channels
automatically when the card doesn't support it natively.
This will lead to some problems for some applications like quake or
wine, especially if they use the card only in the MMAP mode.
In such a case, you can change the behavior of PCM per application by
writing a command to the proc file. There is a proc file for each PCM
stream, /proc/asound/cardX/pcmY[cp]/oss, where X is the card number
(zero-based), Y the PCM device number (zero-based), and 'p' is for
playback and 'c' for capture, respectively. Note that this proc file
exists only after snd-pcm-oss module is loaded.
The command sequence has the following syntax:
app_name fragments fragment_size [options]
app_name is the name of application with (higher priority) or without
path.
fragments specifies the number of fragments or zero if no specific
number is given.
fragment_size is the size of fragment in bytes or zero if not given.
options is the optional parameters. The following options are
available:
disable the application tries to open a pcm device for
this channel but does not want to use it.
direct don't use plugins
block force block open mode
non-block force non-block open mode
The disable option is useful when one stream direction (playback or
capture) is not handled correctly by the application although the
hardware itself does support both directions.
The direct option is used, as mentioned above, to bypass the automatic
conversion and useful for MMAP-applications.
For example, to playback the first PCM device without plugins for
quake, send a command via echo like the following:
% echo "quake 0 0 direct" > /proc/asound/card0/pcm0p/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.
The block and non-block options are used to change the behavior of
opening the device file.
As default, ALSA behaves as defined in POSIX, i.e. blocks the file
when it's busy until the device becomes free (unless O_NONBLOCK is
specified). Some applications assume the non-block open behavior,
which are actually implemented in some real OSS drivers.
This blocking behavior can be changed globally via nonblock_open
module option of snd-pcm-oss. For using the non-block mode as default
for OSS devices, define like the following:
options snd-pcm-oss nonblock_open=1
You can check the currently defined configuration by reading the proc
file. The read image can be sent to the proc file again, hence you
can save the current configuration
% cat /proc/asound/card0/pcm0p/oss > /somewhere/oss-cfg
and restore it like
% cat /somewhere/oss-cfg > /proc/asound/card0/pcm0p/oss
Also, for clearing all the current configuration, send "erase" command
as below:
% echo "erase" > /proc/asound/card0/pcm0p/oss
Mixer Elements
==============
Since ALSA has completely different mixer interface, the emulation of
OSS mixer is relatively complicated. ALSA builds up a mixer element
from several different ALSA (mixer) controls based on the name
string. For example, the volume element SOUND_MIXER_PCM is composed
from "PCM Playback Volume" and "PCM Playback Switch" controls for the
playback direction and from "PCM Capture Volume" and "PCM Capture
Switch" for the capture directory (if exists). When the PCM volume of
OSS is changed, all the volume and switch controls above are adjusted
automatically.
As default, ALSA uses the following control for OSS volumes:
OSS volume ALSA control Index
-----------------------------------------------------
SOUND_MIXER_VOLUME Master 0
SOUND_MIXER_BASS Tone Control - Bass 0
SOUND_MIXER_TREBLE Tone Control - Treble 0
SOUND_MIXER_SYNTH Synth 0
SOUND_MIXER_PCM PCM 0
SOUND_MIXER_SPEAKER PC Speaker 0
SOUND_MIXER_LINE Line 0
SOUND_MIXER_MIC Mic 0
SOUND_MIXER_CD CD 0
SOUND_MIXER_IMIX Monitor Mix 0
SOUND_MIXER_ALTPCM PCM 1
SOUND_MIXER_RECLEV (not assigned)
SOUND_MIXER_IGAIN Capture 0
SOUND_MIXER_OGAIN Playback 0
SOUND_MIXER_LINE1 Aux 0
SOUND_MIXER_LINE2 Aux 1
SOUND_MIXER_LINE3 Aux 2
SOUND_MIXER_DIGITAL1 Digital 0
SOUND_MIXER_DIGITAL2 Digital 1
SOUND_MIXER_DIGITAL3 Digital 2
SOUND_MIXER_PHONEIN Phone 0
SOUND_MIXER_PHONEOUT Phone 1
SOUND_MIXER_VIDEO Video 0
SOUND_MIXER_RADIO Radio 0
SOUND_MIXER_MONITOR Monitor 0
The second column is the base-string of the corresponding ALSA
control. In fact, the controls with "XXX [Playback|Capture]
[Volume|Switch]" will be checked in addition.
The current assignment of these mixer elements is listed in the proc
file, /proc/asound/cardX/mixer_oss, which will be like the following
VOLUME "Master" 0
BASS "" 0
TREBLE "" 0
SYNTH "" 0
PCM "PCM" 0
...
where the first column is the OSS volume element, the second column
the base-string of the corresponding ALSA control, and the third the
control index. When the string is empty, it means that the
corresponding OSS control is not available.
For changing the assignment, you can write the configuration to this
proc file. For example, to map "Wave Playback" to the PCM volume,
send the command like the following:
% echo 'VOLUME "Wave Playback" 0' > /proc/asound/card0/mixer_oss
The command is exactly as same as listed in the proc file. You can
change one or more elements, one volume per line. In the last
example, both "Wave Playback Volume" and "Wave Playback Switch" will
be affected when PCM volume is changed.
Like the case of PCM proc file, the permission of proc files depend on
the module options of snd. you'll likely need to be superuser for
sending the command above.
As well as in the case of PCM proc file, you can save and restore the
current mixer configuration by reading and writing the whole file
image.
Unsupported Features
====================
MMAP on ICE1712 driver
----------------------
ICE1712 supports only the unconventional format, interleaved
10-channels 24bit (packed in 32bit) format. Therefore you cannot mmap
the buffer as the conventional (mono or 2-channels, 8 or 16bit) format
on OSS.
USB devices
-----------
Some USB devices support only 24bit format packed in 3bytes. This
format is not supported by OSS and no conversion is provided by kernel
OSS emulation. You can use the user-space OSS emulation via libaoss
instead.
......@@ -22,7 +22,6 @@
*
*/
#include "control.h"
#include "pcm.h"
/* IO ports */
......@@ -166,25 +165,40 @@ const snd_pcm_ops_t *snd_ad1848_get_pcm_ops(int direction);
int snd_ad1848_mixer(ad1848_t * chip);
void snd_ad1848_interrupt(int irq, void *dev_id, struct pt_regs *regs);
#define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_ad1848_info_single, \
.get = snd_ad1848_get_single, .put = snd_ad1848_put_single, \
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
/* exported mixer stuffs */
enum { AD1848_MIX_SINGLE, AD1848_MIX_DOUBLE, AD1848_MIX_CAPTURE };
#define AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) \
((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24))
#define AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) \
((left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22))
int snd_ad1848_add_ctl(ad1848_t *chip, const char *name, int index, int type, unsigned long value);
int snd_ad1848_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
int snd_ad1848_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
int snd_ad1848_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
/* for ease of use */
struct ad1848_mix_elem {
const char *name;
int index;
int type;
unsigned long private_value;
};
#define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
{ .name = xname, \
.index = xindex, \
.type = AD1848_MIX_SINGLE, \
.private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) }
#define AD1848_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_ad1848_info_double, \
.get = snd_ad1848_get_double, .put = snd_ad1848_put_double, \
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
int snd_ad1848_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
int snd_ad1848_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
int snd_ad1848_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
{ .name = xname, \
.index = xindex, \
.type = AD1848_MIX_DOUBLE, \
.private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) }
static inline int snd_ad1848_add_ctl_elem(ad1848_t *chip, const struct ad1848_mix_elem *c)
{
return snd_ad1848_add_ctl(chip, c->name, c->index, c->type, c->private_value);
}
#ifdef CONFIG_SND_DEBUG
void snd_ad1848_debug(ad1848_t *chip);
......
......@@ -314,4 +314,49 @@ int snd_sb16_capture_open(snd_pcm_substream_t *substream);
int snd_sb16_playback_close(snd_pcm_substream_t *substream);
int snd_sb16_capture_close(snd_pcm_substream_t *substream);
/* exported mixer stuffs */
enum {
SB_MIX_SINGLE,
SB_MIX_DOUBLE,
SB_MIX_INPUT_SW,
SB_MIX_CAPTURE_PRO,
SB_MIX_CAPTURE_DT019X
};
#define SB_MIXVAL_DOUBLE(left_reg, right_reg, left_shift, right_shift, mask) \
((left_reg) | ((right_reg) << 8) | ((left_shift) << 16) | ((right_shift) << 19) | ((mask) << 24))
#define SB_MIXVAL_SINGLE(reg, shift, mask) \
((reg) | ((shift) << 16) | ((mask) << 24))
#define SB_MIXVAL_INPUT_SW(reg1, reg2, left_shift, right_shift) \
((reg1) | ((reg2) << 8) | ((left_shift) << 16) | ((right_shift) << 24))
int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsigned long value);
/* for ease of use */
struct sbmix_elem {
const char *name;
int type;
unsigned long private_value;
};
#define SB_SINGLE(xname, reg, shift, mask) \
{ .name = xname, \
.type = SB_MIX_SINGLE, \
.private_value = SB_MIXVAL_SINGLE(reg, shift, mask) }
#define SB_DOUBLE(xname, left_reg, right_reg, left_shift, right_shift, mask) \
{ .name = xname, \
.type = SB_MIX_DOUBLE, \
.private_value = SB_MIXVAL_DOUBLE(left_reg, right_reg, left_shift, right_shift, mask) }
#define SB16_INPUT_SW(xname, reg1, reg2, left_shift, right_shift) \
{ .name = xname, \
.type = SB_MIX_INPUT_SW, \
.private_value = SB_MIXVAL_INPUT_SW(reg1, reg2, left_shift, right_shift) }
static inline int snd_sbmixer_add_ctl_elem(sb_t *chip, const struct sbmix_elem *c)
{
return snd_sbmixer_add_ctl(chip, c->name, 0, c->type, c->private_value);
}
#endif /* __SOUND_SB_H */
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc6"
#define CONFIG_SND_DATE " (Wed Jan 08 17:04:59 2003 UTC)"
#define CONFIG_SND_DATE " (Fri Jan 10 18:18:43 2003 UTC)"
......@@ -1061,7 +1061,7 @@ snd_info_entry_t *snd_info_create_device(const char *name, unsigned int number,
return NULL;
entry->content = SNDRV_INFO_CONTENT_DEVICE;
entry->mode = mode;
entry->c.device.major = major;
entry->c.device.major = _major;
entry->c.device.minor = minor;
down(&info_mutex);
p = create_proc_entry(entry->name, entry->mode, snd_proc_dev);
......@@ -1085,7 +1085,7 @@ snd_info_entry_t *snd_info_create_device(const char *name, unsigned int number,
char dname[32];
sprintf(dname, "snd/%s", name);
devfs_register(NULL, dname, DEVFS_FL_DEFAULT,
major, minor, mode,
_major, minor, mode,
&snd_fops, NULL);
}
#endif
......
......@@ -28,6 +28,7 @@
#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/ad1848.h>
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <asm/io.h>
......@@ -996,7 +997,7 @@ static int snd_ad1848_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *
return change;
}
int snd_ad1848_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
static int snd_ad1848_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
int mask = (kcontrol->private_value >> 16) & 0xff;
......@@ -1007,7 +1008,7 @@ int snd_ad1848_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo
return 0;
}
int snd_ad1848_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
static int snd_ad1848_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ad1848_t *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
......@@ -1024,7 +1025,7 @@ int snd_ad1848_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucon
return 0;
}
int snd_ad1848_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
static int snd_ad1848_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ad1848_t *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
......@@ -1047,7 +1048,7 @@ int snd_ad1848_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucon
return change;
}
int snd_ad1848_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
static int snd_ad1848_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
int mask = (kcontrol->private_value >> 24) & 0xff;
......@@ -1058,7 +1059,7 @@ int snd_ad1848_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo
return 0;
}
int snd_ad1848_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
static int snd_ad1848_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ad1848_t *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
......@@ -1080,7 +1081,7 @@ int snd_ad1848_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucon
return 0;
}
int snd_ad1848_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
static int snd_ad1848_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ad1848_t *chip = snd_kcontrol_chip(kcontrol);
unsigned long flags;
......@@ -1117,9 +1118,47 @@ int snd_ad1848_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucon
return change;
}
#define AD1848_CONTROLS (sizeof(snd_ad1848_controls)/sizeof(snd_kcontrol_new_t))
/*
*/
int snd_ad1848_add_ctl(ad1848_t *chip, const char *name, int index, int type, unsigned long value)
{
static snd_kcontrol_new_t newctls[] = {
[AD1848_MIX_SINGLE] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_ad1848_info_single,
.get = snd_ad1848_get_single,
.put = snd_ad1848_put_single,
},
[AD1848_MIX_DOUBLE] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_ad1848_info_double,
.get = snd_ad1848_get_double,
.put = snd_ad1848_put_double,
},
[AD1848_MIX_CAPTURE] = {
.info = snd_ad1848_info_mux,
.get = snd_ad1848_get_mux,
.put = snd_ad1848_put_mux,
},
};
snd_kcontrol_t *ctl;
int err;
ctl = snd_ctl_new1(&newctls[type], chip);
if (! ctl)
return -ENOMEM;
strncpy(ctl->id.name, name, sizeof(ctl->id.name)-1);
ctl->id.index = index;
ctl->private_value = value;
if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
snd_ctl_free_one(ctl);
return err;
}
return 0;
}
static snd_kcontrol_new_t snd_ad1848_controls[] = {
static struct ad1848_mix_elem snd_ad1848_controls[] = {
AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1),
AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
......@@ -1128,11 +1167,8 @@ AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGH
AD1848_DOUBLE("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
AD1848_DOUBLE("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
.info = snd_ad1848_info_mux,
.get = snd_ad1848_get_mux,
.put = snd_ad1848_put_mux,
.type = AD1848_MIX_CAPTURE,
},
AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0),
AD1848_SINGLE("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0)
......@@ -1151,10 +1187,10 @@ int snd_ad1848_mixer(ad1848_t *chip)
strcpy(card->mixername, pcm->name);
for (idx = 0; idx < AD1848_CONTROLS; idx++) {
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ad1848_controls[idx], chip))) < 0)
for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++)
if ((err = snd_ad1848_add_ctl_elem(chip, &snd_ad1848_controls[idx])) < 0)
return err;
}
return 0;
}
......@@ -1168,12 +1204,7 @@ EXPORT_SYMBOL(snd_ad1848_create);
EXPORT_SYMBOL(snd_ad1848_pcm);
EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
EXPORT_SYMBOL(snd_ad1848_mixer);
EXPORT_SYMBOL(snd_ad1848_info_single);
EXPORT_SYMBOL(snd_ad1848_get_single);
EXPORT_SYMBOL(snd_ad1848_put_single);
EXPORT_SYMBOL(snd_ad1848_info_double);
EXPORT_SYMBOL(snd_ad1848_get_double);
EXPORT_SYMBOL(snd_ad1848_put_double);
EXPORT_SYMBOL(snd_ad1848_add_ctl);
/*
* INIT part
......
......@@ -57,6 +57,13 @@
#define SNDRV_GET_ID
#include <sound/initval.h>
/*
*/
#define ENABLE_SB_MIXER
#define PLAYBACK_ON_SB
/*
*/
MODULE_AUTHOR("George Talusan <gstalusan@uwaterloo.ca>");
MODULE_DESCRIPTION("C-Media CMI8330");
MODULE_LICENSE("GPL");
......@@ -129,8 +136,12 @@ MODULE_PARM_SYNTAX(wssdma, SNDRV_DMA8_DESC ",prefers:{0}");
static unsigned char snd_cmi8330_image[((CMI8330_CDINGAIN)-16) + 1] =
{
0x0, /* 16 - recording mux */
0x40, /* 17 - mute mux */
0x40, /* 16 - recording mux (SB-mixer-enabled) */
#ifdef ENABLE_SB_MIXER
0x40, /* 17 - mute mux (Mode2) */
#else
0x0, /* 17 - mute mux */
#endif
0x0, /* 18 - vol */
0x0, /* 19 - master volume */
0x0, /* 20 - line-in volume */
......@@ -142,6 +153,8 @@ static unsigned char snd_cmi8330_image[((CMI8330_CDINGAIN)-16) + 1] =
0x0 /* 26 - cd-in rec gain */
};
typedef int (*snd_pcm_open_callback_t)(snd_pcm_substream_t *);
struct snd_cmi8330 {
#ifdef __ISAPNP__
struct isapnp_dev *cap;
......@@ -152,10 +165,11 @@ struct snd_cmi8330 {
sb_t *sb;
snd_pcm_t *pcm;
snd_pcm_ops_t playback_ops;
int (*playback_open)(snd_pcm_substream_t *);
snd_pcm_ops_t capture_ops;
int (*capture_open)(snd_pcm_substream_t *);
struct snd_cmi8330_stream {
snd_pcm_ops_t ops;
snd_pcm_open_callback_t open;
void *private_data; /* sb or wss */
} streams[2];
};
static snd_card_t *snd_cmi8330_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
......@@ -182,9 +196,8 @@ ISAPNP_CARD_TABLE(snd_cmi8330_pnpids);
#endif
#define CMI8330_CONTROLS (sizeof(snd_cmi8330_controls)/sizeof(snd_kcontrol_new_t))
static snd_kcontrol_new_t snd_cmi8330_controls[] __devinitdata = {
static struct ad1848_mix_elem snd_cmi8330_controls[] __initdata = {
AD1848_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0),
AD1848_SINGLE("Loud Playback Switch", 0, CMI8330_MUTEMUX, 6, 1, 1),
AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
......@@ -212,16 +225,79 @@ AD1848_SINGLE("IEC958 Input Capture Switch", 0, CMI8330_RMUX3D, 7, 1, 1),
AD1848_SINGLE("IEC958 Input Playback Switch", 0, CMI8330_MUTEMUX, 7, 1, 1),
};
static int __init snd_cmi8330_mixer(snd_card_t *card, ad1848_t *chip)
#ifdef ENABLE_SB_MIXER
static struct sbmix_elem cmi8330_sb_mixers[] __initdata = {
SB_DOUBLE("SB Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15),
SB_DOUBLE("SB PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
SB_DOUBLE("SB Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
SB_DOUBLE("SB CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
SB_DOUBLE("SB CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
SB_DOUBLE("SB Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
SB_DOUBLE("SB Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
SB_SINGLE("SB Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
SB_SINGLE("SB Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
SB_SINGLE("SB PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
SB_DOUBLE("SB Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
SB_DOUBLE("SB Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
};
static unsigned char cmi8330_sb_init_values[][2] __initdata = {
{ SB_DSP4_MASTER_DEV + 0, 0 },
{ SB_DSP4_MASTER_DEV + 1, 0 },
{ SB_DSP4_PCM_DEV + 0, 0 },
{ SB_DSP4_PCM_DEV + 1, 0 },
{ SB_DSP4_SYNTH_DEV + 0, 0 },
{ SB_DSP4_SYNTH_DEV + 1, 0 },
{ SB_DSP4_INPUT_LEFT, 0 },
{ SB_DSP4_INPUT_RIGHT, 0 },
{ SB_DSP4_OUTPUT_SW, 0 },
{ SB_DSP4_SPEAKER_DEV, 0 },
};
static int __init cmi8330_add_sb_mixers(sb_t *chip)
{
int idx, err;
unsigned long flags;
spin_lock_irqsave(&chip->mixer_lock, flags);
snd_sbmixer_write(chip, 0x00, 0x00); /* mixer reset */
spin_unlock_irqrestore(&chip->mixer_lock, flags);
/* mute and zero volume channels */
for (idx = 0; idx < ARRAY_SIZE(cmi8330_sb_init_values); idx++) {
spin_lock_irqsave(&chip->mixer_lock, flags);
snd_sbmixer_write(chip, cmi8330_sb_init_values[idx][0],
cmi8330_sb_init_values[idx][1]);
spin_unlock_irqrestore(&chip->mixer_lock, flags);
}
for (idx = 0; idx < ARRAY_SIZE(cmi8330_sb_mixers); idx++) {
if ((err = snd_sbmixer_add_ctl_elem(chip, &cmi8330_sb_mixers[idx])) < 0)
return err;
}
return 0;
}
#endif
static int __init snd_cmi8330_mixer(snd_card_t *card, struct snd_cmi8330 *acard)
{
int idx, err;
strcpy(card->mixername, "CMI8330/C3D");
for (idx = 0; idx < CMI8330_CONTROLS; idx++)
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cmi8330_controls[idx], chip))) < 0)
for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) {
if ((err = snd_ad1848_add_ctl_elem(acard->wss, &snd_cmi8330_controls[idx])) < 0)
return err;
}
#ifdef ENABLE_SB_MIXER
if ((err = cmi8330_add_sb_mixers(acard->sb)) < 0)
return err;
#endif
return 0;
}
......@@ -316,13 +392,21 @@ static void snd_cmi8330_deactivate(struct snd_cmi8330 *acard)
*
*/
#ifdef PLAYBACK_ON_SB
#define CMI_SB_STREAM SNDRV_PCM_STREAM_PLAYBACK
#define CMI_AD_STREAM SNDRV_PCM_STREAM_CAPTURE
#else
#define CMI_SB_STREAM SNDRV_PCM_STREAM_CAPTURE
#define CMI_AD_STREAM SNDRV_PCM_STREAM_PLAYBACK
#endif
static int snd_cmi8330_playback_open(snd_pcm_substream_t * substream)
{
struct snd_cmi8330 *chip = (struct snd_cmi8330 *)_snd_pcm_substream_chip(substream);
/* replace the private_data and call the original open callback */
substream->private_data = chip->sb;
return chip->playback_open(substream);
substream->private_data = chip->streams[SNDRV_PCM_STREAM_PLAYBACK].private_data;
return chip->streams[SNDRV_PCM_STREAM_PLAYBACK].open(substream);
}
static int snd_cmi8330_capture_open(snd_pcm_substream_t * substream)
......@@ -330,8 +414,8 @@ static int snd_cmi8330_capture_open(snd_pcm_substream_t * substream)
struct snd_cmi8330 *chip = (struct snd_cmi8330 *)_snd_pcm_substream_chip(substream);
/* replace the private_data and call the original open callback */
substream->private_data = chip->wss;
return chip->capture_open(substream);
substream->private_data = chip->streams[SNDRV_PCM_STREAM_CAPTURE].private_data;
return chip->streams[SNDRV_PCM_STREAM_CAPTURE].open(substream);
}
static void snd_cmi8330_pcm_free(snd_pcm_t *pcm)
......@@ -344,27 +428,33 @@ static int __init snd_cmi8330_pcm(snd_card_t *card, struct snd_cmi8330 *chip)
snd_pcm_t *pcm;
const snd_pcm_ops_t *ops;
int err;
static snd_pcm_open_callback_t cmi_open_callbacks[2] = {
snd_cmi8330_playback_open,
snd_cmi8330_capture_open
};
if ((err = snd_pcm_new(card, "CMI8330", 0, 1, 1, &pcm)) < 0)
return err;
strcpy(pcm->name, "CMI8330");
pcm->private_data = chip;
pcm->private_free = snd_cmi8330_pcm_free;
/* playback - SB16 */
ops = snd_sb16dsp_get_pcm_ops(SNDRV_PCM_STREAM_PLAYBACK);
chip->playback_ops = *ops;
chip->playback_open = ops->open;
chip->playback_ops.open = snd_cmi8330_playback_open;
/* capture - AD1848 */
ops = snd_ad1848_get_pcm_ops(SNDRV_PCM_STREAM_CAPTURE);
chip->capture_ops = *ops;
chip->capture_open = ops->open;
chip->capture_ops.open = snd_cmi8330_capture_open;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &chip->playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &chip->capture_ops);
/* SB16 */
ops = snd_sb16dsp_get_pcm_ops(CMI_SB_STREAM);
chip->streams[CMI_SB_STREAM].ops = *ops;
chip->streams[CMI_SB_STREAM].open = ops->open;
chip->streams[CMI_SB_STREAM].ops.open = cmi_open_callbacks[CMI_SB_STREAM];
chip->streams[CMI_SB_STREAM].private_data = chip->sb;
/* AD1848 */
ops = snd_ad1848_get_pcm_ops(CMI_AD_STREAM);
chip->streams[CMI_AD_STREAM].ops = *ops;
chip->streams[CMI_AD_STREAM].open = ops->open;
chip->streams[CMI_AD_STREAM].ops.open = cmi_open_callbacks[CMI_AD_STREAM];
chip->streams[CMI_AD_STREAM].private_data = chip->wss;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK].ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &chip->streams[SNDRV_PCM_STREAM_CAPTURE].ops);
snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 128*1024);
chip->pcm = pcm;
......@@ -457,22 +547,18 @@ static int __init snd_cmi8330_probe(int dev)
snd_card_free(card);
return -ENODEV;
}
memcpy(&acard->wss->image[16], &snd_cmi8330_image, sizeof(snd_cmi8330_image));
spin_lock_irqsave(&acard->wss->reg_lock, flags);
snd_ad1848_out(acard->wss, AD1848_MISC_INFO, /* switch on MODE2 */
acard->wss->image[AD1848_MISC_INFO] |= 0x40);
snd_ad1848_out(acard->wss, AD1848_MISC_INFO, 0x40); /* switch on MODE2 */
for (i = CMI8330_RMUX3D; i <= CMI8330_CDINGAIN; i++)
snd_ad1848_out(acard->wss, i, snd_cmi8330_image[i - CMI8330_RMUX3D]);
spin_unlock_irqrestore(&acard->wss->reg_lock, flags);
if ((err = snd_cmi8330_mixer(card, acard->wss)) < 0) {
if ((err = snd_cmi8330_mixer(card, acard)) < 0) {
snd_printk("failed to create mixers\n");
snd_card_free(card);
return err;
}
spin_lock_irqsave(&acard->wss->reg_lock, flags);
for (i = CMI8330_RMUX3D; i <= CMI8330_CDINGAIN; i++)
snd_ad1848_out(acard->wss, i, acard->wss->image[i]);
spin_unlock_irqrestore(&acard->wss->reg_lock, flags);
if ((err = snd_cmi8330_pcm(card, acard)) < 0) {
snd_printk("failed to create pcms\n");
......
......@@ -297,6 +297,7 @@ EXPORT_SYMBOL(snd_sbdsp_create);
EXPORT_SYMBOL(snd_sbmixer_write);
EXPORT_SYMBOL(snd_sbmixer_read);
EXPORT_SYMBOL(snd_sbmixer_new);
EXPORT_SYMBOL(snd_sbmixer_add_ctl);
/*
* INIT part
......
......@@ -60,14 +60,6 @@ unsigned char snd_sbmixer_read(sb_t *chip, unsigned char reg)
* Single channel mixer element
*/
#define SB_SINGLE(xname, reg, shift, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.info = snd_sbmixer_info_single, \
.get = snd_sbmixer_get_single, \
.put = snd_sbmixer_put_single, \
.private_value = reg | (shift << 16) | (mask << 24) }
static int snd_sbmixer_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
int mask = (kcontrol->private_value >> 24) & 0xff;
......@@ -120,14 +112,6 @@ static int snd_sbmixer_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_
* Double channel mixer element
*/
#define SB_DOUBLE(xname, left_reg, right_reg, left_shift, right_shift, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.info = snd_sbmixer_info_double, \
.get = snd_sbmixer_get_double, \
.put = snd_sbmixer_put_double, \
.private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) }
static int snd_sbmixer_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
int mask = (kcontrol->private_value >> 24) & 0xff;
......@@ -364,14 +348,6 @@ static int snd_sb8mixer_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
* SB16 input switch
*/
#define SB16_INPUT_SW(xname, reg1, reg2, left_shift, right_shift) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.info = snd_sb16mixer_info_input_sw, \
.get = snd_sb16mixer_get_input_sw, \
.put = snd_sb16mixer_put_input_sw, \
.private_value = reg1 | (reg2 << 8) | (left_shift << 16) | (right_shift << 24) }
static int snd_sb16mixer_info_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
......@@ -431,61 +407,114 @@ static int snd_sb16mixer_put_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
return change;
}
#define SB20_CONTROLS (sizeof(snd_sb20_controls)/sizeof(snd_kcontrol_new_t *))
static snd_kcontrol_new_t snd_sb20_ctl_master_play_vol =
/*
*/
/*
*/
int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsigned long value)
{
static snd_kcontrol_new_t newctls[] = {
[SB_MIX_SINGLE] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_sbmixer_info_single,
.get = snd_sbmixer_get_single,
.put = snd_sbmixer_put_single,
},
[SB_MIX_DOUBLE] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_sbmixer_info_double,
.get = snd_sbmixer_get_double,
.put = snd_sbmixer_put_double,
},
[SB_MIX_INPUT_SW] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_sb16mixer_info_input_sw,
.get = snd_sb16mixer_get_input_sw,
.put = snd_sb16mixer_put_input_sw,
},
[SB_MIX_CAPTURE_PRO] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_sb8mixer_info_mux,
.get = snd_sb8mixer_get_mux,
.put = snd_sb8mixer_put_mux,
},
[SB_MIX_CAPTURE_DT019X] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_dt019x_input_sw_info,
.get = snd_dt019x_input_sw_get,
.put = snd_dt019x_input_sw_put,
},
};
snd_kcontrol_t *ctl;
int err;
ctl = snd_ctl_new1(&newctls[type], chip);
if (! ctl)
return -ENOMEM;
strncpy(ctl->id.name, name, sizeof(ctl->id.name)-1);
ctl->id.index = index;
ctl->private_value = value;
if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
snd_ctl_free_one(ctl);
return err;
}
return 0;
}
/*
* SB 2.0 specific mixer elements
*/
static struct sbmix_elem snd_sb20_ctl_master_play_vol =
SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
static snd_kcontrol_new_t snd_sb20_ctl_pcm_play_vol =
static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
static snd_kcontrol_new_t snd_sb20_ctl_synth_play_vol =
static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
static snd_kcontrol_new_t snd_sb20_ctl_cd_play_vol =
static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
static snd_kcontrol_new_t *snd_sb20_controls[] = {
static struct sbmix_elem *snd_sb20_controls[] = {
&snd_sb20_ctl_master_play_vol,
&snd_sb20_ctl_pcm_play_vol,
&snd_sb20_ctl_synth_play_vol,
&snd_sb20_ctl_cd_play_vol
};
#define SB20_INIT_VALUES (sizeof(snd_sb20_init_values)/sizeof(unsigned char)/2)
static unsigned char snd_sb20_init_values[][2] = {
{ SB_DSP20_MASTER_DEV, 0 },
{ SB_DSP20_FM_DEV, 0 },
};
#define SBPRO_CONTROLS (sizeof(snd_sbpro_controls)/sizeof(snd_kcontrol_new_t *))
static snd_kcontrol_new_t snd_sbpro_ctl_master_play_vol =
/*
* SB Pro specific mixer elements
*/
static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
static snd_kcontrol_new_t snd_sbpro_ctl_pcm_play_vol =
static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
static snd_kcontrol_new_t snd_sbpro_ctl_pcm_play_filter =
static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
static snd_kcontrol_new_t snd_sbpro_ctl_synth_play_vol =
static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
static snd_kcontrol_new_t snd_sbpro_ctl_cd_play_vol =
static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
static snd_kcontrol_new_t snd_sbpro_ctl_line_play_vol =
static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
static snd_kcontrol_new_t snd_sbpro_ctl_mic_play_vol =
static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
static snd_kcontrol_new_t snd_sbpro_ctl_capture_source =
static struct sbmix_elem snd_sbpro_ctl_capture_source =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
.info = snd_sb8mixer_info_mux,
.get = snd_sb8mixer_get_mux,
.put = snd_sb8mixer_put_mux,
.type = SB_MIX_CAPTURE_PRO
};
static snd_kcontrol_new_t snd_sbpro_ctl_capture_filter =
static struct sbmix_elem snd_sbpro_ctl_capture_filter =
SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
static snd_kcontrol_new_t snd_sbpro_ctl_capture_low_filter =
static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
static snd_kcontrol_new_t *snd_sbpro_controls[] = {
static struct sbmix_elem *snd_sbpro_controls[] = {
&snd_sbpro_ctl_master_play_vol,
&snd_sbpro_ctl_pcm_play_vol,
&snd_sbpro_ctl_pcm_play_filter,
......@@ -498,58 +527,57 @@ static snd_kcontrol_new_t *snd_sbpro_controls[] = {
&snd_sbpro_ctl_capture_low_filter
};
#define SBPRO_INIT_VALUES (sizeof(snd_sbpro_init_values)/sizeof(unsigned char)/2)
static unsigned char snd_sbpro_init_values[][2] = {
{ SB_DSP_MASTER_DEV, 0 },
{ SB_DSP_PCM_DEV, 0 },
{ SB_DSP_FM_DEV, 0 },
};
#define SB16_CONTROLS (sizeof(snd_sb16_controls)/sizeof(snd_kcontrol_new_t *))
static snd_kcontrol_new_t snd_sb16_ctl_master_play_vol =
/*
* SB16 specific mixer elements
*/
static struct sbmix_elem snd_sb16_ctl_master_play_vol =
SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
static snd_kcontrol_new_t snd_sb16_ctl_3d_enhance_switch =
static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
static snd_kcontrol_new_t snd_sb16_ctl_tone_bass =
static struct sbmix_elem snd_sb16_ctl_tone_bass =
SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
static snd_kcontrol_new_t snd_sb16_ctl_tone_treble =
static struct sbmix_elem snd_sb16_ctl_tone_treble =
SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
static snd_kcontrol_new_t snd_sb16_ctl_pcm_play_vol =
static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
static snd_kcontrol_new_t snd_sb16_ctl_synth_capture_route =
static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
static snd_kcontrol_new_t snd_sb16_ctl_synth_play_vol =
static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
static snd_kcontrol_new_t snd_sb16_ctl_cd_capture_route =
static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
static snd_kcontrol_new_t snd_sb16_ctl_cd_play_switch =
static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
static snd_kcontrol_new_t snd_sb16_ctl_cd_play_vol =
static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
static snd_kcontrol_new_t snd_sb16_ctl_line_capture_route =
static struct sbmix_elem snd_sb16_ctl_line_capture_route =
SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
static snd_kcontrol_new_t snd_sb16_ctl_line_play_switch =
static struct sbmix_elem snd_sb16_ctl_line_play_switch =
SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
static snd_kcontrol_new_t snd_sb16_ctl_line_play_vol =
static struct sbmix_elem snd_sb16_ctl_line_play_vol =
SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
static snd_kcontrol_new_t snd_sb16_ctl_mic_capture_route =
static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
static snd_kcontrol_new_t snd_sb16_ctl_mic_play_switch =
static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
static snd_kcontrol_new_t snd_sb16_ctl_mic_play_vol =
static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
static snd_kcontrol_new_t snd_sb16_ctl_pc_speaker_vol =
static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
static snd_kcontrol_new_t snd_sb16_ctl_capture_vol =
static struct sbmix_elem snd_sb16_ctl_capture_vol =
SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
static snd_kcontrol_new_t snd_sb16_ctl_play_vol =
static struct sbmix_elem snd_sb16_ctl_play_vol =
SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
static snd_kcontrol_new_t snd_sb16_ctl_auto_mic_gain =
static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
static snd_kcontrol_new_t *snd_sb16_controls[] = {
static struct sbmix_elem *snd_sb16_controls[] = {
&snd_sb16_ctl_master_play_vol,
&snd_sb16_ctl_3d_enhance_switch,
&snd_sb16_ctl_tone_bass,
......@@ -572,8 +600,6 @@ static snd_kcontrol_new_t *snd_sb16_controls[] = {
&snd_sb16_ctl_auto_mic_gain
};
#define SB16_INIT_VALUES (sizeof(snd_sb16_init_values)/sizeof(unsigned char)/2)
static unsigned char snd_sb16_init_values[][2] = {
{ SB_DSP4_MASTER_DEV + 0, 0 },
{ SB_DSP4_MASTER_DEV + 1, 0 },
......@@ -587,37 +613,34 @@ static unsigned char snd_sb16_init_values[][2] = {
{ SB_DSP4_SPEAKER_DEV, 0 },
};
#define DT019X_CONTROLS (sizeof(snd_dt019x_controls)/sizeof(snd_kcontrol_new_t *))
static snd_kcontrol_new_t snd_dt019x_ctl_master_play_vol =
/*
* DT019x specific mixer elements
*/
static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
static snd_kcontrol_new_t snd_dt019x_ctl_pcm_play_vol =
static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
static snd_kcontrol_new_t snd_dt019x_ctl_synth_play_vol =
static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
static snd_kcontrol_new_t snd_dt019x_ctl_cd_play_vol =
static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
static snd_kcontrol_new_t snd_dt019x_ctl_mic_play_vol =
static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
static snd_kcontrol_new_t snd_dt019x_ctl_pc_speaker_vol =
static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7);
static snd_kcontrol_new_t snd_dt019x_ctl_line_play_vol =
static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
static snd_kcontrol_new_t snd_dt019x_ctl_pcm_play_switch =
static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
static snd_kcontrol_new_t snd_dt019x_ctl_synth_play_switch =
static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
static snd_kcontrol_new_t snd_dt019x_ctl_capture_source =
static struct sbmix_elem snd_dt019x_ctl_capture_source =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
.info = snd_dt019x_input_sw_info,
.get = snd_dt019x_input_sw_get,
.put = snd_dt019x_input_sw_put,
.type = SB_MIX_CAPTURE_DT019X
};
static snd_kcontrol_new_t *snd_dt019x_controls[] = {
static struct sbmix_elem *snd_dt019x_controls[] = {
&snd_dt019x_ctl_master_play_vol,
&snd_dt019x_ctl_pcm_play_vol,
&snd_dt019x_ctl_synth_play_vol,
......@@ -633,8 +656,6 @@ static snd_kcontrol_new_t *snd_dt019x_controls[] = {
&snd_dt019x_ctl_capture_source
};
#define DT019X_INIT_VALUES (sizeof(snd_dt019x_init_values)/sizeof(unsigned char)/2)
static unsigned char snd_dt019x_init_values[][2] = {
{ SB_DT019X_MASTER_DEV, 0 },
{ SB_DT019X_PCM_DEV, 0 },
......@@ -647,35 +668,36 @@ static unsigned char snd_dt019x_init_values[][2] = {
{ SB_DT019X_CAPTURE_SW, 0x06 },
};
/*
* ALS4000 specific mixer elements
*/
/* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl ! */
static snd_kcontrol_new_t snd_als4000_ctl_mono_output_switch =
static struct sbmix_elem snd_als4000_ctl_mono_output_switch =
SB_SINGLE("Mono Output Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
/* FIXME: mono input switch also available on DT019X ? */
static snd_kcontrol_new_t snd_als4000_ctl_mono_input_switch =
static struct sbmix_elem snd_als4000_ctl_mono_input_switch =
SB_SINGLE("Mono Input Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
static snd_kcontrol_new_t snd_als4000_ctl_mic_20db_boost =
static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
static snd_kcontrol_new_t snd_als4000_ctl_mixer_out_to_in =
static struct sbmix_elem snd_als4000_ctl_mixer_out_to_in =
SB_SINGLE("Mixer Out To In", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
/* FIXME: 3D needs much more sophisticated controls, many more features ! */
static snd_kcontrol_new_t snd_als4000_ctl_3d_output_switch =
static struct sbmix_elem snd_als4000_ctl_3d_output_switch =
SB_SINGLE("3D Output Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
static snd_kcontrol_new_t snd_als4000_ctl_3d_output_ratio =
static struct sbmix_elem snd_als4000_ctl_3d_output_ratio =
SB_SINGLE("3D Output Ratio", SB_ALS4000_3D_SND_FX, 0, 0x07);
static snd_kcontrol_new_t snd_als4000_ctl_3d_poweroff_switch =
static struct sbmix_elem snd_als4000_ctl_3d_poweroff_switch =
SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
static snd_kcontrol_new_t snd_als4000_ctl_3d_delay =
static struct sbmix_elem snd_als4000_ctl_3d_delay =
SB_SINGLE("3D Delay", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
#if NOT_AVAILABLE
static snd_kcontrol_new_t snd_als4000_ctl_fmdac =
static struct sbmix_elem snd_als4000_ctl_fmdac =
SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
static snd_kcontrol_new_t snd_als4000_ctl_qsound =
static struct sbmix_elem snd_als4000_ctl_qsound =
SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
#endif
#define ALS4000_CONTROLS (sizeof(snd_als4000_controls)/sizeof(snd_kcontrol_new_t *))
static snd_kcontrol_new_t *snd_als4000_controls[] = {
static struct sbmix_elem *snd_als4000_controls[] = {
&snd_sb16_ctl_master_play_vol,
&snd_dt019x_ctl_pcm_play_switch,
&snd_sb16_ctl_pcm_play_vol,
......@@ -709,8 +731,6 @@ static snd_kcontrol_new_t *snd_als4000_controls[] = {
#endif
};
#define ALS4000_INIT_VALUES (sizeof(snd_als4000_init_values)/sizeof(unsigned char)/2)
static unsigned char snd_als4000_init_values[][2] = {
{ SB_DSP4_MASTER_DEV + 0, 0 },
{ SB_DSP4_MASTER_DEV + 1, 0 },
......@@ -726,8 +746,11 @@ static unsigned char snd_als4000_init_values[][2] = {
{ SB_ALS4000_MIC_IN_GAIN, 0 },
};
/*
*/
static int snd_sbmixer_init(sb_t *chip,
snd_kcontrol_new_t **controls,
struct sbmix_elem **controls,
int controls_count,
unsigned char map[][2],
int map_count,
......@@ -750,7 +773,7 @@ static int snd_sbmixer_init(sb_t *chip,
}
for (idx = 0; idx < controls_count; idx++) {
if ((err = snd_ctl_add(card, snd_ctl_new1(controls[idx], chip))) < 0)
if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
return err;
}
snd_component_add(card, name);
......@@ -773,37 +796,47 @@ int snd_sbmixer_new(sb_t *chip)
case SB_HW_20:
case SB_HW_201:
if ((err = snd_sbmixer_init(chip,
snd_sb20_controls, SB20_CONTROLS,
snd_sb20_init_values, SB20_INIT_VALUES,
snd_sb20_controls,
ARRAY_SIZE(snd_sb20_controls),
snd_sb20_init_values,
ARRAY_SIZE(snd_sb20_init_values),
"CTL1335")) < 0)
return err;
break;
case SB_HW_PRO:
if ((err = snd_sbmixer_init(chip,
snd_sbpro_controls, SBPRO_CONTROLS,
snd_sbpro_init_values, SBPRO_INIT_VALUES,
snd_sbpro_controls,
ARRAY_SIZE(snd_sbpro_controls),
snd_sbpro_init_values,
ARRAY_SIZE(snd_sbpro_init_values),
"CTL1345")) < 0)
return err;
break;
case SB_HW_16:
case SB_HW_ALS100:
if ((err = snd_sbmixer_init(chip,
snd_sb16_controls, SB16_CONTROLS,
snd_sb16_init_values, SB16_INIT_VALUES,
snd_sb16_controls,
ARRAY_SIZE(snd_sb16_controls),
snd_sb16_init_values,
ARRAY_SIZE(snd_sb16_init_values),
"CTL1745")) < 0)
return err;
break;
case SB_HW_ALS4000:
if ((err = snd_sbmixer_init(chip,
snd_als4000_controls, ALS4000_CONTROLS,
snd_als4000_init_values, ALS4000_INIT_VALUES,
snd_als4000_controls,
ARRAY_SIZE(snd_als4000_controls),
snd_als4000_init_values,
ARRAY_SIZE(snd_als4000_init_values),
"ALS4000")) < 0)
return err;
break;
case SB_HW_DT019X:
if ((err = snd_sbmixer_init(chip,
snd_dt019x_controls, DT019X_CONTROLS,
snd_dt019x_init_values, DT019X_INIT_VALUES,
snd_dt019x_controls,
ARRAY_SIZE(snd_dt019x_controls),
snd_dt019x_init_values,
ARRAY_SIZE(snd_dt019x_init_values),
"DT019X")) < 0)
break;
default:
......
......@@ -30,6 +30,7 @@
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/ad1848.h>
#include <sound/control.h>
#define SNDRV_LEGACY_FIND_FREE_IRQ
#define SNDRV_LEGACY_FIND_FREE_DMA
#define SNDRV_GET_ID
......@@ -176,9 +177,7 @@ static int __init snd_sgalaxy_detect(int dev, int irq, int dma)
return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
}
#define SGALAXY_CONTROLS 2
static snd_kcontrol_new_t snd_sgalaxy_controls[2] = {
static struct ad1848_mix_elem snd_sgalaxy_controls[] = {
AD1848_DOUBLE("Aux Playback Switch", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
AD1848_DOUBLE("Aux Playback Volume", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
};
......@@ -211,8 +210,8 @@ static int __init snd_sgalaxy_mixer(ad1848_t *chip)
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
return err;
/* build AUX2 input */
for (idx = 0; idx < SGALAXY_CONTROLS; idx++) {
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_sgalaxy_controls[idx], chip))) < 0)
for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
if ((err = snd_ad1848_add_ctl_elem(chip, &snd_sgalaxy_controls[idx])) < 0)
return err;
}
return 0;
......
......@@ -116,10 +116,10 @@ config SND_ENS1371
Sound Blaster PCI 64 or 128 soundcards.
config SND_ES1938
tristate "ESS ES1938/1946 (Solo-1)"
tristate "ESS ES1938/1946/1969 (Solo-1)"
depends on SND && SOUND_GAMEPORT
help
Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946)
Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946, ES1969)
soundcard.
config SND_ES1968
......
......@@ -1278,6 +1278,9 @@ static int __devinit snd_intel8x0_pcm_mic(intel8x0_t *chip, int device, snd_pcm_
sprintf(pcm->name, "%s - MIC ADC", chip->card->shortname);
chip->pcm_mic = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 0, 128*1024);
if (rpcm)
*rpcm = pcm;
return 0;
......@@ -1312,6 +1315,9 @@ static int __devinit snd_intel8x0_pcm_mic2(intel8x0_t *chip, int device, snd_pcm
sprintf(pcm->name, "%s - MIC2 ADC", chip->card->shortname);
chip->pcm_mic2 = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 0, 128*1024);
if (rpcm)
*rpcm = pcm;
return 0;
......@@ -1346,6 +1352,9 @@ static int __devinit snd_intel8x0_pcm_capture2(intel8x0_t *chip, int device, snd
sprintf(pcm->name, "%s - ADC2", chip->card->shortname);
chip->pcm2 = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 0, 128*1024);
if (rpcm)
*rpcm = pcm;
return 0;
......@@ -1380,6 +1389,9 @@ static int __devinit snd_intel8x0_pcm_spdif(intel8x0_t *chip, int device, snd_pc
sprintf(pcm->name, "%s - IEC958", chip->card->shortname);
chip->pcm_spdif = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
if (rpcm)
*rpcm = pcm;
return 0;
......@@ -1415,6 +1427,9 @@ static int __devinit snd_intel8x0_ali_spdif(intel8x0_t *chip, int device, snd_pc
sprintf(pcm->name, "%s - IEC958", chip->card->shortname);
chip->pcm_spdif = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
if (rpcm)
*rpcm = pcm;
return 0;
......@@ -1449,6 +1464,9 @@ static int __devinit snd_intel8x0_ali_ac97spdif(intel8x0_t *chip, int device, sn
sprintf(pcm->name, "%s - AC97 IEC958", chip->card->shortname);
chip->pcm_ac97spdif = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
if (rpcm)
*rpcm = pcm;
return 0;
......@@ -1790,6 +1808,10 @@ static int snd_intel8x0_ich_chip_init(intel8x0_t *chip)
} while (time_after_eq(end_time, jiffies));
__ok3:
if (chip->device_type == DEVICE_SIS) {
/* unmute the output on SIS7012 */
iputword(chip, 0x4c, igetword(chip, 0x4c) | 1);
}
return 0;
}
......@@ -2476,6 +2498,8 @@ static struct pci_driver joystick_driver = {
.id_table = snd_intel8x0_joystick_ids,
.probe = snd_intel8x0_joystick_probe,
};
static int have_joystick;
#endif
static int __init alsa_card_intel8x0_init(void)
......@@ -2489,7 +2513,13 @@ static int __init alsa_card_intel8x0_init(void)
return err;
}
#if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI)
pci_module_init(&joystick_driver);
if (pci_module_init(&joystick_driver) < 0) {
snd_printdd(KERN_INFO "no joystick found\n");
have_joystick = 0;
} else {
snd_printdd(KERN_INFO "joystick(s) found\n");
have_joystick = 1;
}
#endif
return 0;
......@@ -2499,7 +2529,8 @@ static void __exit alsa_card_intel8x0_exit(void)
{
pci_unregister_driver(&driver);
#if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI)
pci_unregister_driver(&joystick_driver);
if (have_joystick)
pci_unregister_driver(&joystick_driver);
#endif
}
......
/*
* ALSA driver for RME Digi32, Digi32/8 and Digi32 PRO audio interfaces
*
* Copyright (c) 2002 Martin Langer <martin-langer@gmx.de>
* Copyright (c) 2002, 2003 Martin Langer <martin-langer@gmx.de>
*
* Thanks to : Anders Torger <torger@ludd.luth.se>,
* Henk Hesselink <henk@anda.nl>
......@@ -70,6 +70,7 @@
#include <sound/asoundef.h>
#define SNDRV_GET_ID
#include <sound/initval.h>
#include <sound/info.h>
#include <asm/io.h>
......@@ -256,8 +257,6 @@ snd_rme32_capture_pointer(snd_pcm_substream_t * substream);
static void snd_rme32_proc_init(rme32_t * rme32);
static void snd_rme32_proc_done(rme32_t * rme32);
static int snd_rme32_create_switches(snd_card_t * card, rme32_t * rme32);
static inline unsigned int snd_rme32_playback_ptr(rme32_t * rme32)
......@@ -1830,7 +1829,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Clock Mode",
.name = "Sample Clock Source",
.info = snd_rme32_info_clockmode_control,
.get = snd_rme32_get_clockmode_control,
.put = snd_rme32_put_clockmode_control
......
......@@ -23,6 +23,26 @@
*
*/
/*
* Changes:
*
* Dec. 19, 2002 Takashi Iwai <tiwai@suse.de>
* - use the DSX channels for the first pcm playback.
* (on VIA8233, 8233C and 8235 only)
* this will allow you play simultaneously up to 4 streams.
* multi-channel playback is assigned to the second device
* on these chips.
* - support the secondary capture (on VIA8233/C,8235)
* - SPDIF support
* the DSX3 channel can be used for SPDIF output.
* on VIA8233A, this channel is assigned to the second pcm
* playback.
* the card config of alsa-lib will assign the correct
* device for applications.
* - clean up the code, separate low-level initialization
* routines for each chipset.
*/
#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
......@@ -48,7 +68,7 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("VIA VT82xx audio");
MODULE_LICENSE("GPL");
MODULE_CLASSES("{sound}");
MODULE_DEVICES("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/B/C}}");
MODULE_DEVICES("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
......@@ -183,6 +203,13 @@ DEFINE_VIA_REGSET(CAPTURE_8233, 0x60);
#define VIA_TBL_BIT_FLAG 0x40000000
#define VIA_TBL_BIT_EOL 0x80000000
/*
*/
typedef struct _snd_via82xx via82xx_t;
typedef struct via_dev viadev_t;
#define chip_t via82xx_t
/*
* pcm stream
*/
......@@ -194,18 +221,20 @@ struct snd_via_sg_table {
#define VIA_TABLE_SIZE 255
typedef struct {
unsigned long reg_offset;
struct via_dev {
unsigned int reg_offset;
int direction; /* playback = 0, capture = 1 */
snd_pcm_substream_t *substream;
int running;
unsigned int tbl_entries; /* # descriptors */
u32 *table; /* physical address + flag */
dma_addr_t table_addr;
struct snd_via_sg_table *idx_table;
/* for recovery from the unexpected pointer */
unsigned int lastpos;
unsigned int bufsize;
unsigned int bufsize2;
} viadev_t;
};
/*
......@@ -218,7 +247,7 @@ static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
unsigned int periods, unsigned int fragsize)
{
unsigned int i, idx, ofs, rest;
struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
if (! dev->table) {
/* the start of each lists must be aligned to 8 bytes,
......@@ -297,8 +326,13 @@ static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
enum { TYPE_VIA686 = 1, TYPE_VIA8233 };
typedef struct _snd_via82xx via82xx_t;
#define chip_t via82xx_t
#define VIA_MAX_DEVS 7 /* 4 playback, 1 multi, 2 capture */
struct via_rate_lock {
spinlock_t lock;
int rate;
int used;
};
struct _snd_via82xx {
int irq;
......@@ -314,9 +348,10 @@ struct _snd_via82xx {
struct pci_dev *pci;
snd_card_t *card;
snd_pcm_t *pcm;
viadev_t playback;
viadev_t capture;
int num_devs;
int playback_devno, multi_devno, capture_devno;
viadev_t devs[VIA_MAX_DEVS];
struct via_rate_lock rates[2]; /* playback and capture */
snd_rawmidi_t *rmidi;
......@@ -361,7 +396,7 @@ static int snd_via82xx_codec_ready(via82xx_t *chip, int secondary)
if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY))
return val & 0xffff;
}
snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via82xx_codec_xread(chip));
snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via82xx_codec_xread(chip));
return -EIO;
}
......@@ -377,7 +412,7 @@ static int snd_via82xx_codec_valid(via82xx_t *chip, int secondary)
if ((val = snd_via82xx_codec_xread(chip)) & stat)
return val & 0xffff;
}
snd_printk("codec_valid: codec %i is not valid [0x%x]\n", secondary, snd_via82xx_codec_xread(chip));
snd_printk(KERN_ERR "codec_valid: codec %i is not valid [0x%x]\n", secondary, snd_via82xx_codec_xread(chip));
return -EIO;
}
......@@ -452,11 +487,57 @@ static void snd_via82xx_channel_reset(via82xx_t *chip, viadev_t *viadev)
viadev->lastpos = 0;
}
static int snd_via82xx_trigger(via82xx_t *chip, viadev_t *viadev, int cmd)
/*
* Interrupt handler
*/
static void snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
via82xx_t *chip = snd_magic_cast(via82xx_t, dev_id, return);
unsigned int status;
int i;
spin_lock(&chip->reg_lock);
if (chip->chip_type == TYPE_VIA686) {
/* check mpu401 interrupt */
status = inl(VIAREG(chip, SGD_SHADOW));
if ((status & 0x00000077) == 0) {
spin_unlock(&chip->reg_lock);
if (chip->rmidi != NULL)
snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
return;
}
}
/* check status for each stream */
for (i = 0; i < chip->num_devs; i++) {
viadev_t *viadev = &chip->devs[i];
if (inb(chip->port + viadev->reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG)) {
outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
if (viadev->substream && viadev->running) {
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(viadev->substream);
spin_lock(&chip->reg_lock);
}
}
}
spin_unlock(&chip->reg_lock);
}
/*
* PCM callbacks
*/
/*
* trigger callback
*/
static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
unsigned char val;
unsigned long port = chip->port + viadev->reg_offset;
if (chip->chip_type == TYPE_VIA8233)
val = VIA_REG_CTRL_INT;
else
......@@ -487,114 +568,104 @@ static int snd_via82xx_trigger(via82xx_t *chip, viadev_t *viadev, int cmd)
}
static int snd_via82xx_set_format(via82xx_t *chip, viadev_t *viadev,
snd_pcm_substream_t *substream)
/*
* pointer callbacks
*/
/*
* calculate the linear position at the given sg-buffer index and the rest count
*/
static inline unsigned int calc_linear_pos(viadev_t *viadev, unsigned int idx, unsigned int count)
{
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long port = chip->port + viadev->reg_offset;
unsigned int size, res;
snd_via82xx_channel_reset(chip, viadev);
size = viadev->idx_table[idx].size;
res = viadev->idx_table[idx].offset + size - count;
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
switch (chip->chip_type) {
case TYPE_VIA686:
outb(VIA_REG_TYPE_AUTOSTART |
(runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
(runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) |
VIA_REG_TYPE_INT_EOL |
VIA_REG_TYPE_INT_FLAG, port + VIA_REG_OFFSET_TYPE);
break;
case TYPE_VIA8233:
if (viadev->reg_offset == VIA_REG_MULTPLAY_STATUS) {
unsigned int slots;
int fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
fmt |= runtime->channels << 4;
outb(fmt, port + VIA_REG_OFFSET_TYPE);
/* set sample number to slot 3, 4, 7, 8, 6, 9 */
switch (runtime->channels) {
case 1: slots = (1<<0) | (1<<4); break;
case 2: slots = (1<<0) | (2<<4); break;
case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
default: slots = 0; break;
}
/* STOP index is never reached */
outl(0xff000000 | slots, port + VIA_REG_OFFSET_STOP_IDX);
/* check the validity of the calculated position */
if (size < count || (res < viadev->lastpos && (res >= viadev->bufsize2 || viadev->lastpos < viadev->bufsize2))) {
#ifdef POINTER_DEBUG
printk("fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos, viadev->bufsize2, viadev->idx_table[idx].offset, viadev->idx_table[idx].size, count);
#endif
/* count register returns full size when end of buffer is reached */
if (size != count) {
snd_printd(KERN_ERR "invalid via82xx_cur_ptr, using last valid pointer\n");
res = viadev->lastpos;
} else {
outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) |
(runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) |
0xff000000, /* STOP index is never reached */
port + VIA_REG_OFFSET_STOP_IDX);
res = viadev->idx_table[idx].offset + size;
if (res < viadev->lastpos && (res >= viadev->bufsize2 || viadev->lastpos < viadev->bufsize2)) {
snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), using last valid pointer\n");
res = viadev->lastpos;
}
}
break;
}
return 0;
viadev->lastpos = res; /* remember the last positiion */
if (res >= viadev->bufsize)
res -= viadev->bufsize;
return res;
}
/*
* Interrupt handler
* get the current pointer on via686
*/
static inline void snd_via82xx_update(via82xx_t *chip, viadev_t *viadev)
static snd_pcm_uframes_t snd_via686_pcm_pointer(snd_pcm_substream_t *substream)
{
outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
if (viadev->substream && viadev->running) {
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(viadev->substream);
spin_lock(&chip->reg_lock);
}
}
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
unsigned int idx, ptr, count, res;
static void snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
via82xx_t *chip = snd_magic_cast(via82xx_t, dev_id, return);
unsigned int status;
snd_assert(viadev->tbl_entries, return 0);
if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
return 0;
spin_lock(&chip->reg_lock);
if (chip->chip_type == TYPE_VIA686) {
/* check mpu401 interrupt */
status = inl(VIAREG(chip, SGD_SHADOW));
if ((status & 0x00000077) == 0) {
spin_unlock(&chip->reg_lock);
if (chip->rmidi != NULL)
snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
return;
}
}
/* check status for each stream */
if (inb(chip->port + chip->playback.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via82xx_update(chip, &chip->playback);
if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via82xx_update(chip, &chip->capture);
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
/* The via686a does not have the current index register,
* so we need to calculate the index from CURR_PTR.
*/
ptr = inl(VIAREG(chip, OFFSET_CURR_PTR) + viadev->reg_offset);
if (ptr <= (unsigned int)viadev->table_addr)
idx = 0;
else /* CURR_PTR holds the address + 8 */
idx = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
res = calc_linear_pos(viadev, idx, count);
spin_unlock(&chip->reg_lock);
return bytes_to_frames(substream->runtime, res);
}
/*
* PCM part
* get the current pointer on via823x
*/
static int snd_via82xx_playback_trigger(snd_pcm_substream_t * substream,
int cmd)
static snd_pcm_uframes_t snd_via8233_pcm_pointer(snd_pcm_substream_t *substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
unsigned int idx, count, res;
snd_assert(viadev->tbl_entries, return 0);
if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
return 0;
spin_lock(&chip->reg_lock);
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset);
idx = count >> 24;
count &= 0xffffff;
res = calc_linear_pos(viadev, idx, count);
spin_unlock(&chip->reg_lock);
return snd_via82xx_trigger(chip, &chip->playback, cmd);
return bytes_to_frames(substream->runtime, res);
}
static int snd_via82xx_capture_trigger(snd_pcm_substream_t * substream,
int cmd)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
return snd_via82xx_trigger(chip, &chip->capture, cmd);
}
/*
* hw_params callback:
* allocate the buffer and build up the buffer description table
*/
static int snd_via82xx_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? &chip->playback : &chip->capture;
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
int err;
err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
......@@ -605,131 +676,184 @@ static int snd_via82xx_hw_params(snd_pcm_substream_t * substream,
params_period_bytes(hw_params));
if (err < 0)
return err;
return err;
return 0;
}
/*
* hw_free callback:
* clean up the buffer description table and release the buffer
*/
static int snd_via82xx_hw_free(snd_pcm_substream_t * substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? &chip->playback : &chip->capture;
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
clean_via_table(viadev, substream, chip->pci);
snd_pcm_sgbuf_free(substream);
return 0;
}
static int snd_via82xx_playback_prepare(snd_pcm_substream_t * substream)
/*
* prepare callback for playback and capture on via686
*/
static void via686_setup_format(via82xx_t *chip, viadev_t *viadev, snd_pcm_runtime_t *runtime)
{
unsigned long port = chip->port + viadev->reg_offset;
snd_via82xx_channel_reset(chip, viadev);
/* this must be set after channel_reset */
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
outb(VIA_REG_TYPE_AUTOSTART |
(runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
(runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) |
VIA_REG_TYPE_INT_EOL |
VIA_REG_TYPE_INT_FLAG, port + VIA_REG_OFFSET_TYPE);
}
static int snd_via686_playback_prepare(snd_pcm_substream_t *substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
snd_pcm_runtime_t *runtime = substream->runtime;
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);
if (chip->chip_type == TYPE_VIA8233 &&
chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
unsigned int tmp;
/* I don't understand this stuff but its from the documentation and this way it works */
outb(0 , VIAREG(chip, PLAYBACK_VOLUME_L));
outb(0 , VIAREG(chip, PLAYBACK_VOLUME_R));
tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX));
}
return snd_via82xx_set_format(chip, &chip->playback, substream);
via686_setup_format(chip, viadev, runtime);
return 0;
}
static int snd_via82xx_capture_prepare(snd_pcm_substream_t * substream)
static int snd_via686_capture_prepare(snd_pcm_substream_t *substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
if (chip->chip_type == TYPE_VIA8233)
outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
return snd_via82xx_set_format(chip, &chip->capture, substream);
via686_setup_format(chip, viadev, runtime);
return 0;
}
static inline unsigned int snd_via82xx_cur_ptr(via82xx_t *chip, viadev_t *viadev)
/*
* lock the current rate
*/
static int via_lock_rate(struct via_rate_lock *rec, int rate)
{
unsigned int val, ptr, count, res;
snd_assert(viadev->tbl_entries, return 0);
if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
return 0;
spin_lock(&chip->reg_lock);
switch (chip->chip_type) {
case TYPE_VIA686:
count &= 0xffffff;
/* The via686a does not have the current index register,
* so we need to calculate the index from CURR_PTR.
*/
ptr = inl(VIAREG(chip, OFFSET_CURR_PTR) + viadev->reg_offset);
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
if (ptr <= (unsigned int)viadev->table_addr)
val = 0;
else /* CURR_PTR holds the address + 8 */
val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
break;
case TYPE_VIA8233:
default:
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset);
val = count >> 24;
count &= 0xffffff;
break;
}
/* convert to the linear position */
ptr = viadev->idx_table[val].size;
res = viadev->idx_table[val].offset + ptr - count;
if (ptr < count || (res < viadev->lastpos && (res >= viadev->bufsize2 || viadev->lastpos < viadev->bufsize2))) {
#ifdef POINTER_DEBUG
printk("fail: val = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n", val, viadev->tbl_entries, viadev->lastpos, viadev->bufsize2, viadev->idx_table[val].offset, viadev->idx_table[val].size, count);
#endif
/* VIA8233 count register returns full size when end of buffer is reached */
if (ptr != count) {
snd_printk("invalid via82xx_cur_ptr, using last valid pointer\n");
res = viadev->lastpos;
} else {
res = viadev->idx_table[val].offset + ptr;
if (res < viadev->lastpos && (res >= viadev->bufsize2 || viadev->lastpos < viadev->bufsize2)) {
snd_printk("invalid via82xx_cur_ptr (2), using last valid pointer\n");
res = viadev->lastpos;
}
spin_lock(&rec->lock);
if (rec->rate) {
if (rec->rate != rate && rec->used > 1) {
spin_unlock(&rec->lock);
return -EINVAL;
}
}
} else
rec->rate = rate;
spin_unlock(&rec->lock);
return 0;
}
viadev->lastpos = res;
spin_unlock(&chip->reg_lock);
/*
* prepare callback for DSX playback on via823x
*/
static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream)
{
via82xx_t *chip = snd_pcm_substream_chip(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;
return res;
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 */
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);
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 */
0xff000000, /* STOP index is never reached */
port + VIA_REG_OFFSET_STOP_IDX);
return 0;
}
static snd_pcm_uframes_t snd_via82xx_playback_pointer(snd_pcm_substream_t * substream)
/*
* prepare callback for multi-channel playback on via823x
*/
static int snd_via8233_multi_prepare(snd_pcm_substream_t *substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, snd_via82xx_cur_ptr(chip, &chip->playback));
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
unsigned long port = chip->port + viadev->reg_offset;
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned int slots;
int fmt;
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);
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_via82xx_channel_reset(chip, viadev);
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
fmt |= runtime->channels << 4;
outb(fmt, port + VIA_REG_OFFSET_TYPE);
/* set sample number to slot 3, 4, 7, 8, 6, 9 */
/* corresponding to FL, FR, RL, RR, C, LFE ?? */
switch (runtime->channels) {
case 1: slots = (1<<0) | (1<<4); break;
case 2: slots = (1<<0) | (2<<4); break;
case 3: slots = (1<<0) | (2<<4) | (5<<8); break;
case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
case 5: slots = (1<<0) | (2<<4) | (5<<8) | (3<<12) | (4<<16); break;
case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
default: slots = 0; break;
}
/* STOP index is never reached */
outl(0xff000000 | slots, port + VIA_REG_OFFSET_STOP_IDX);
return 0;
}
static snd_pcm_uframes_t snd_via82xx_capture_pointer(snd_pcm_substream_t * substream)
/*
* prepare callback for capture on via823x
*/
static int snd_via8233_capture_prepare(snd_pcm_substream_t *substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, snd_via82xx_cur_ptr(chip, &chip->capture));
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
unsigned long port = chip->port + viadev->reg_offset;
snd_pcm_runtime_t *runtime = substream->runtime;
if (via_lock_rate(&chip->rates[1], runtime->rate) < 0)
return -EINVAL;
snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
snd_via82xx_channel_reset(chip, viadev);
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) |
(runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) |
0xff000000, /* STOP index is never reached */
port + VIA_REG_OFFSET_STOP_IDX);
return 0;
}
static snd_pcm_hardware_t snd_via82xx_playback =
/*
* pcm hardware definition, identical for both playback and capture
*/
static snd_pcm_hardware_t snd_via82xx_hw =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = 0,
.rate_min = 8000,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
......@@ -741,151 +865,310 @@ static snd_pcm_hardware_t snd_via82xx_playback =
.fifo_size = 0,
};
static snd_pcm_hardware_t snd_via82xx_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = 0,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = VIA_TABLE_SIZE / 2,
.fifo_size = 0,
};
static unsigned int channels[] = {
1, 2, 4, 6
};
#define CHANNELS sizeof(channels) / sizeof(channels[0])
static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
.count = CHANNELS,
.list = channels,
.mask = 0,
};
static int snd_via82xx_playback_open(snd_pcm_substream_t * substream)
/*
* open callback skeleton
*/
static int snd_via82xx_pcm_open(via82xx_t *chip, viadev_t *viadev, snd_pcm_substream_t * substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
unsigned long flags;
struct via_rate_lock *ratep;
runtime->hw = snd_via82xx_hw;
/* set the hw rate condition */
ratep = &chip->rates[viadev->direction];
spin_lock_irqsave(&ratep->lock, flags);
ratep->used++;
if (! ratep->rate) {
int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC;
runtime->hw.rates = chip->ac97->rates[idx];
if (runtime->hw.rates & SNDRV_PCM_RATE_8000)
runtime->hw.rate_min = 8000;
} else {
/* a fixed rate */
runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate;
}
spin_unlock_irqrestore(&ratep->lock, flags);
chip->playback.substream = substream;
runtime->hw = snd_via82xx_playback;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_FRONT_DAC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
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)
return err;
if (chip->chip_type == TYPE_VIA8233) {
runtime->hw.channels_max = 6;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
}
runtime->private_data = viadev;
viadev->substream = substream;
return 0;
}
static int snd_via82xx_capture_open(snd_pcm_substream_t * substream)
/*
* open callback for playback on via686 and via823x DSX
*/
static int snd_via82xx_playback_open(snd_pcm_substream_t * substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
viadev_t *viadev = &chip->devs[chip->playback_devno + substream->number];
return snd_via82xx_pcm_open(chip, viadev, substream);
}
/*
* open callback for playback on via823x multi-channel
*/
static int snd_via8233_multi_open(snd_pcm_substream_t * substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
viadev_t *viadev = &chip->devs[chip->multi_devno];
int err;
/* channels constraint for VIA8233A
* 3 and 5 channels are not supported
*/
static unsigned int channels[] = {
1, 2, 4, 6
};
static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
};
chip->capture.substream = substream;
runtime->hw = snd_via82xx_capture;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_ADC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0)
return err;
substream->runtime->hw.channels_max = 6;
if (chip->revision == VIA_REV_8233A)
snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
return 0;
}
static int snd_via82xx_playback_close(snd_pcm_substream_t * substream)
/*
* open callback for capture on via686 and via823x
*/
static int snd_via82xx_capture_open(snd_pcm_substream_t * substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
chip->playback.substream = NULL;
snd_pcm_sgbuf_delete(substream);
return 0;
viadev_t *viadev = &chip->devs[chip->capture_devno + substream->pcm->device];
return snd_via82xx_pcm_open(chip, viadev, substream);
}
static int snd_via82xx_capture_close(snd_pcm_substream_t * substream)
/*
* close callback
*/
static int snd_via82xx_pcm_close(snd_pcm_substream_t * substream)
{
via82xx_t *chip = snd_pcm_substream_chip(substream);
chip->capture.substream = NULL;
viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
unsigned long flags;
struct via_rate_lock *ratep;
/* release the rate lock */
ratep = &chip->rates[viadev->direction];
spin_lock_irqsave(&ratep->lock, flags);
ratep->used--;
if (! ratep->used)
ratep->rate = 0;
spin_unlock_irqrestore(&ratep->lock, flags);
viadev->substream = NULL;
snd_pcm_sgbuf_delete(substream);
return 0;
}
static snd_pcm_ops_t snd_via82xx_playback_ops = {
/* via686 playback callbacks */
static snd_pcm_ops_t snd_via686_playback_ops = {
.open = snd_via82xx_playback_open,
.close = snd_via82xx_playback_close,
.close = snd_via82xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.prepare = snd_via82xx_playback_prepare,
.trigger = snd_via82xx_playback_trigger,
.pointer = snd_via82xx_playback_pointer,
.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,
};
static snd_pcm_ops_t snd_via82xx_capture_ops = {
/* via686 capture callbacks */
static snd_pcm_ops_t snd_via686_capture_ops = {
.open = snd_via82xx_capture_open,
.close = snd_via82xx_capture_close,
.close = snd_via82xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.prepare = snd_via82xx_capture_prepare,
.trigger = snd_via82xx_capture_trigger,
.pointer = snd_via82xx_capture_pointer,
.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,
};
static void snd_via82xx_pcm_free(snd_pcm_t *pcm)
/* via823x DSX playback callbacks */
static snd_pcm_ops_t snd_via8233_playback_ops = {
.open = snd_via82xx_playback_open,
.close = snd_via82xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.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,
};
/* via823x multi-channel playback callbacks */
static snd_pcm_ops_t snd_via8233_multi_ops = {
.open = snd_via8233_multi_open,
.close = snd_via82xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.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,
};
/* via823x capture callbacks */
static snd_pcm_ops_t snd_via8233_capture_ops = {
.open = snd_via82xx_capture_open,
.close = snd_via82xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.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,
};
/*
* create pcm instances for VIA8233, 8233C and 8235 (not 8233A)
*/
static int __devinit snd_via8233_pcm_new(via82xx_t *chip)
{
via82xx_t *chip = snd_magic_cast(via82xx_t, pcm->private_data, return);
chip->pcm = NULL;
snd_pcm_t *pcm;
int i, err;
chip->playback_devno = 0; /* x 4 */
chip->multi_devno = 4; /* x 1 */
chip->capture_devno = 5; /* x 2 */
chip->num_devs = 7;
/* PCM #0: 4 DSX playbacks and 1 capture */
err = snd_pcm_new(chip->card, chip->card->shortname, 0, 4, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
pcm->private_data = chip;
strcpy(pcm->name, chip->card->shortname);
/* set up playbacks */
for (i = 0; i < 4; i++) {
chip->devs[i].reg_offset = 0x10 * i;
chip->devs[i].direction = 0;
}
/* capture */
chip->devs[chip->capture_devno].reg_offset = VIA_REG_CAPTURE_8233_STATUS;
chip->devs[chip->capture_devno].direction = 1;
/* PCM #1: multi-channel playback and 2nd capture */
err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_multi_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
pcm->private_data = chip;
strcpy(pcm->name, chip->card->shortname);
/* set up playback */
chip->devs[chip->multi_devno].reg_offset = VIA_REG_MULTPLAY_STATUS;
chip->devs[chip->multi_devno].direction = 0;
/* 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;
return 0;
}
static int __devinit snd_via82xx_pcm(via82xx_t *chip, int device, snd_pcm_t ** rpcm)
/*
* create pcm instances for VIA8233A
*/
static int __devinit snd_via8233a_pcm_new(via82xx_t *chip)
{
snd_pcm_t *pcm;
int err;
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, chip->card->shortname, device, 1, 1, &pcm);
chip->playback_devno = 0;
chip->multi_devno = 1;
chip->capture_devno = 2;
chip->num_devs = 3;
/* PCM #0: multi-channel playback and capture */
err = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_multi_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
pcm->private_data = chip;
strcpy(pcm->name, chip->card->shortname);
/* set up playback */
chip->devs[chip->multi_devno].reg_offset = VIA_REG_MULTPLAY_STATUS;
chip->devs[chip->multi_devno].direction = 0;
/* capture */
chip->devs[chip->capture_devno].reg_offset = VIA_REG_CAPTURE_8233_STATUS;
chip->devs[chip->capture_devno].direction = 1;
/* PCM #1: DXS3 playback (for spdif) */
err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 0, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops);
pcm->private_data = chip;
strcpy(pcm->name, chip->card->shortname);
/* set up playback */
chip->devs[chip->playback_devno].reg_offset = 0x30;
chip->devs[chip->playback_devno].direction = 0;
return 0;
}
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via82xx_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via82xx_capture_ops);
/*
* create a pcm instance for via686a/b
*/
static int __devinit snd_via686_pcm_new(via82xx_t *chip)
{
snd_pcm_t *pcm;
int err;
chip->playback_devno = 0;
chip->capture_devno = 1;
chip->num_devs = 2;
err = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops);
pcm->private_data = chip;
pcm->private_free = snd_via82xx_pcm_free;
pcm->info_flags = 0;
strcpy(pcm->name, chip->card->shortname);
chip->pcm = pcm;
if (rpcm)
*rpcm = NULL;
chip->devs[0].reg_offset = VIA_REG_PLAYBACK_STATUS;
chip->devs[0].direction = 0;
chip->devs[1].reg_offset = VIA_REG_CAPTURE_STATUS;
chip->devs[1].direction = 1;
return 0;
}
......@@ -911,23 +1194,25 @@ static int snd_via8233_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_ele
static int snd_via8233_capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
via82xx_t *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = inb(VIAREG(chip, CAPTURE_CHANNEL)) & VIA_REG_CAPTURE_CHANNEL_MIC ? 1 : 0;
unsigned long port = chip->port + kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL;
ucontrol->value.enumerated.item[0] = inb(port) & VIA_REG_CAPTURE_CHANNEL_MIC ? 1 : 0;
return 0;
}
static int snd_via8233_capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
via82xx_t *chip = snd_kcontrol_chip(kcontrol);
unsigned long port = chip->port + kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL;
unsigned long flags;
u8 val, oval;
spin_lock_irqsave(&chip->reg_lock, flags);
oval = inb(VIAREG(chip, CAPTURE_CHANNEL));
oval = inb(port);
val = oval & ~VIA_REG_CAPTURE_CHANNEL_MIC;
if (ucontrol->value.enumerated.item[0])
val |= VIA_REG_CAPTURE_CHANNEL_MIC;
if (val != oval)
outb(val, VIAREG(chip, CAPTURE_CHANNEL));
outb(val, port);
spin_unlock_irqrestore(&chip->reg_lock, flags);
return val != oval;
}
......@@ -940,13 +1225,59 @@ static snd_kcontrol_new_t snd_via8233_capture_source __devinitdata = {
.put = snd_via8233_capture_source_put,
};
static int snd_via8233_dxs3_spdif_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_via8233_dxs3_spdif_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
via82xx_t *chip = snd_kcontrol_chip(kcontrol);
u8 val;
pci_read_config_byte(chip->pci, 0x49, &val);
ucontrol->value.integer.value[0] = (val & 0x08) ? 1 : 0;
return 0;
}
static int snd_via8233_dxs3_spdif_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
via82xx_t *chip = snd_kcontrol_chip(kcontrol);
u8 val, oval;
pci_read_config_byte(chip->pci, 0x49, &oval);
val = oval & ~0x08;
if (ucontrol->value.integer.value[0])
val |= 0x08;
if (val != oval) {
pci_write_config_byte(chip->pci, 0x49, val);
return 1;
}
return 0;
}
static snd_kcontrol_new_t snd_via8233_dxs3_spdif_control __devinitdata = {
.name = "IEC958 Output Switch",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_via8233_dxs3_spdif_info,
.get = snd_via8233_dxs3_spdif_get,
.put = snd_via8233_dxs3_spdif_put,
};
/*
*/
static void snd_via82xx_mixer_free_ac97(ac97_t *ac97)
{
via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return);
chip->ac97 = NULL;
}
static int __devinit snd_via82xx_mixer(via82xx_t *chip)
static int __devinit snd_via82xx_mixer_new(via82xx_t *chip)
{
ac97_t ac97;
int err;
......@@ -1010,6 +1341,100 @@ static snd_kcontrol_new_t snd_via82xx_joystick_control __devinitdata = {
.put = snd_via82xx_joystick_put,
};
/*
*
*/
static int snd_via8233_init_misc(via82xx_t *chip, int dev)
{
int i, err, caps;
caps = chip->revision == VIA_REV_8233A ? 1 : 2;
for (i = 0; i < caps; i++) {
snd_via8233_capture_source.index = i;
err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_capture_source, chip));
if (err < 0)
return err;
}
err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip));
if (err < 0)
return err;
return 0;
}
static int snd_via686_init_misc(via82xx_t *chip, int dev)
{
unsigned char legacy, legacy_cfg;
int rev_h = 0;
legacy = chip->old_legacy;
legacy_cfg = chip->old_legacy_cfg;
legacy |= 0x40; /* disable MIDI */
legacy &= ~0x08; /* disable joystick */
if (chip->revision >= 0x20) {
if (check_region(pci_resource_start(chip->pci, 2), 4)) {
rev_h = 0;
legacy &= ~0x80; /* disable PCI I/O 2 */
} else {
rev_h = 1;
legacy |= 0x80; /* enable PCI I/O 2 */
}
}
pci_write_config_byte(chip->pci, 0x42, legacy);
pci_write_config_byte(chip->pci, 0x43, legacy_cfg);
if (rev_h && mpu_port[dev] >= 0x200) { /* force MIDI */
legacy |= 0x02; /* enable MPU */
pci_write_config_dword(chip->pci, 0x18, (mpu_port[dev] & 0xfffc) | 0x01);
} else {
if (rev_h && (legacy & 0x02)) {
mpu_port[dev] = pci_resource_start(chip->pci, 2);
if (mpu_port[dev] < 0x200) /* bad value */
legacy &= ~0x02; /* disable MIDI */
} else {
switch (mpu_port[dev]) { /* force MIDI */
case 0x300:
case 0x310:
case 0x320:
case 0x330:
legacy_cfg &= ~(3 << 2);
legacy_cfg |= (mpu_port[dev] & 0x0030) >> 2;
legacy |= 0x02;
break;
default: /* no, use BIOS settings */
if (legacy & 0x02)
mpu_port[dev] = 0x300 + ((legacy_cfg & 0x000c) << 2);
}
}
}
pci_write_config_byte(chip->pci, 0x42, legacy);
pci_write_config_byte(chip->pci, 0x43, legacy_cfg);
if (legacy & 0x02) {
if (check_region(mpu_port[dev], 2)) {
printk(KERN_WARNING "unable to get MPU-401 port at 0x%lx, skipping\n", mpu_port[dev]);
legacy &= ~0x02;
pci_write_config_byte(chip->pci, 0x42, legacy);
goto __skip_mpu;
}
if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A,
mpu_port[dev], 0,
chip->irq, 0,
&chip->rmidi) < 0) {
printk(KERN_WARNING "unable to initialize MPU-401 at 0x%lx, skipping\n", mpu_port[dev]);
legacy &= ~0x02;
pci_write_config_byte(chip->pci, 0x42, legacy);
goto __skip_mpu;
}
legacy &= ~0x40; /* enable MIDI interrupt */
pci_write_config_byte(chip->pci, 0x42, legacy);
__skip_mpu:
;
}
/* card switches */
return snd_ctl_add(chip->card, snd_ctl_new1(&snd_via82xx_joystick_control, chip));
}
/*
*
*/
......@@ -1102,20 +1527,18 @@ static int __devinit snd_via82xx_chip_init(via82xx_t *chip)
outl(0, chip->port + 0x8c);
}
/* disable interrupts */
snd_via82xx_channel_reset(chip, &chip->playback);
snd_via82xx_channel_reset(chip, &chip->capture);
return 0;
}
static int snd_via82xx_free(via82xx_t *chip)
{
int i;
if (chip->irq < 0)
goto __end_hw;
/* disable interrupts */
snd_via82xx_channel_reset(chip, &chip->playback);
snd_via82xx_channel_reset(chip, &chip->capture);
/* --- */
for (i = 0; i < chip->num_devs; i++)
snd_via82xx_channel_reset(chip, &chip->devs[i]);
synchronize_irq(chip->irq);
__end_hw:
if (chip->res_port) {
......@@ -1160,6 +1583,7 @@ 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);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
......@@ -1185,21 +1609,6 @@ static int __devinit snd_via82xx_create(snd_card_t * card,
pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
synchronize_irq(chip->irq);
/* initialize offsets */
switch (chip->chip_type) {
case TYPE_VIA686:
chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
break;
case TYPE_VIA8233:
/* we use multi-channel playback mode, since this mode is supported
* by all VIA8233 models (and obviously suitable for our purpose).
*/
chip->playback.reg_offset = VIA_REG_MULTPLAY_STATUS;
chip->capture.reg_offset = VIA_REG_CAPTURE_8233_STATUS;
break;
}
if ((err = snd_via82xx_chip_init(chip)) < 0) {
snd_via82xx_free(chip);
return err;
......@@ -1225,9 +1634,9 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
static int dev;
snd_card_t *card;
via82xx_t *chip;
int pcm_dev = 0;
unsigned char revision;
int chip_type;
int err;
int i, err;
if (dev >= SNDRV_CARDS)
return -ENODEV;
......@@ -1241,122 +1650,51 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
return -ENOMEM;
chip_type = pci_id->driver_data;
pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
switch (chip_type) {
case TYPE_VIA686:
strcpy(card->driver, "VIA686A");
strcpy(card->shortname, "VIA 82C686A/B");
break;
case TYPE_VIA8233:
strcpy(card->driver, "VIA8233");
strcpy(card->shortname, "VIA 8233A/C");
if (revision == VIA_REV_8233A) {
strcpy(card->driver, "VIA8233A");
strcpy(card->shortname, "VIA 8233A");
} else {
strcpy(card->driver, "VIA8233");
strcpy(card->shortname, "VIA 8233/C");
}
break;
default:
snd_printk(KERN_ERR "invalid chip type %d\n", chip_type);
snd_card_free(card);
return -EINVAL;
err = -EINVAL;
goto __error;
}
if ((err = snd_via82xx_create(card, pci, chip_type, ac97_clock[dev], &chip)) < 0) {
snd_card_free(card);
return err;
}
if (snd_via82xx_mixer(chip) < 0) {
snd_card_free(card);
return err;
}
if (snd_via82xx_pcm(chip, pcm_dev++, NULL) < 0) {
snd_card_free(card);
return err;
}
#if 0
if (snd_via82xx_pcm_fm(chip, pcm_dev++, NULL) < 0) {
snd_card_free(card);
return err;
}
#endif
if ((err = snd_via82xx_create(card, pci, chip_type, ac97_clock[dev], &chip)) < 0)
goto __error;
if (chip->chip_type == TYPE_VIA686) {
unsigned char legacy, legacy_cfg;
int rev_h = 0;
legacy = chip->old_legacy;
legacy_cfg = chip->old_legacy_cfg;
legacy |= 0x40; /* disable MIDI */
legacy &= ~0x08; /* disable joystick */
if (chip->revision >= 0x20) {
if (check_region(pci_resource_start(pci, 2), 4)) {
rev_h = 0;
legacy &= ~0x80; /* disable PCI I/O 2 */
} else {
rev_h = 1;
legacy |= 0x80; /* enable PCI I/O 2 */
}
}
pci_write_config_byte(pci, 0x42, legacy);
pci_write_config_byte(pci, 0x43, legacy_cfg);
if (rev_h && mpu_port[dev] >= 0x200) { /* force MIDI */
legacy |= 0x02; /* enable MPU */
pci_write_config_dword(pci, 0x18, (mpu_port[dev] & 0xfffc) | 0x01);
} else {
if (rev_h && (legacy & 0x02)) {
mpu_port[dev] = pci_resource_start(pci, 2);
if (mpu_port[dev] < 0x200) /* bad value */
legacy &= ~0x02; /* disable MIDI */
} else {
switch (mpu_port[dev]) { /* force MIDI */
case 0x300:
case 0x310:
case 0x320:
case 0x330:
legacy_cfg &= ~(3 << 2);
legacy_cfg |= (mpu_port[dev] & 0x0030) >> 2;
legacy |= 0x02;
break;
default: /* no, use BIOS settings */
if (legacy & 0x02)
mpu_port[dev] = 0x300 + ((legacy_cfg & 0x000c) << 2);
}
}
}
pci_write_config_byte(pci, 0x42, legacy);
pci_write_config_byte(pci, 0x43, legacy_cfg);
if (legacy & 0x02) {
if (check_region(mpu_port[dev], 2)) {
printk(KERN_WARNING "unable to get MPU-401 port at 0x%lx, skipping\n", mpu_port[dev]);
legacy &= ~0x02;
pci_write_config_byte(pci, 0x42, legacy);
goto __skip_mpu;
}
if (snd_mpu401_uart_new(card, 0, MPU401_HW_VIA686A,
mpu_port[dev], 0,
pci->irq, 0,
&chip->rmidi) < 0) {
printk(KERN_WARNING "unable to initialize MPU-401 at 0x%lx, skipping\n", mpu_port[dev]);
legacy &= ~0x02;
pci_write_config_byte(pci, 0x42, legacy);
goto __skip_mpu;
}
legacy &= ~0x40; /* enable MIDI interrupt */
pci_write_config_byte(pci, 0x42, legacy);
__skip_mpu:
;
}
/* card switches */
err = snd_ctl_add(card, snd_ctl_new1(&snd_via82xx_joystick_control, chip));
if (err < 0) {
snd_card_free(card);
return err;
}
if ((err = snd_via82xx_mixer_new(chip)) < 0)
goto __error;
if (chip_type == TYPE_VIA686) {
if ((err = snd_via686_pcm_new(chip)) < 0 ||
(err = snd_via686_init_misc(chip, dev)) < 0)
goto __error;
} else {
/* VIA8233 */
err = snd_ctl_add(card, snd_ctl_new1(&snd_via8233_capture_source, chip));
if (err < 0) {
snd_card_free(card);
return err;
if (revision == VIA_REV_8233A) {
if ((err = snd_via8233a_pcm_new(chip)) < 0)
goto __error;
} else {
if ((err = snd_via8233_pcm_new(chip)) < 0)
goto __error;
}
if ((err = snd_via8233_init_misc(chip, dev)) < 0)
goto __error;
}
/* disable interrupts */
for (i = 0; i < chip->num_devs; i++)
snd_via82xx_channel_reset(chip, &chip->devs[i]);
sprintf(card->longname, "%s at 0x%lx, irq %d",
card->shortname, chip->port, chip->irq);
......@@ -1368,6 +1706,10 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
pci_set_drvdata(pci, card);
dev++;
return 0;
__error:
snd_card_free(card);
return err;
}
static void __devexit snd_via82xx_remove(struct pci_dev *pci)
......
......@@ -1170,6 +1170,7 @@ static void snd_ymfpci_pcm_spdif_free(snd_pcm_t *pcm)
{
ymfpci_t *chip = snd_magic_cast(ymfpci_t, pcm->private_data, return);
chip->pcm_spdif = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
}
int __devinit snd_ymfpci_pcm_spdif(ymfpci_t *chip, int device, snd_pcm_t ** rpcm)
......@@ -1190,6 +1191,9 @@ int __devinit snd_ymfpci_pcm_spdif(ymfpci_t *chip, int device, snd_pcm_t ** rpcm
pcm->info_flags = 0;
strcpy(pcm->name, "YMFPCI - IEC958");
chip->pcm_spdif = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
if (rpcm)
*rpcm = pcm;
return 0;
......@@ -1210,6 +1214,7 @@ static void snd_ymfpci_pcm_4ch_free(snd_pcm_t *pcm)
{
ymfpci_t *chip = snd_magic_cast(ymfpci_t, pcm->private_data, return);
chip->pcm_4ch = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
}
int __devinit snd_ymfpci_pcm_4ch(ymfpci_t *chip, int device, snd_pcm_t ** rpcm)
......@@ -1230,6 +1235,9 @@ int __devinit snd_ymfpci_pcm_4ch(ymfpci_t *chip, int device, snd_pcm_t ** rpcm)
pcm->info_flags = 0;
strcpy(pcm->name, "YMFPCI - Rear PCM");
chip->pcm_4ch = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
if (rpcm)
*rpcm = pcm;
return 0;
......
......@@ -1953,7 +1953,6 @@ static int snd_usb_roland_ua100_hack_intf(snd_usb_audio_t *chip, int ifnum)
static int snd_usb_roland_ua100_hack(snd_usb_audio_t *chip)
{
static const snd_usb_midi_endpoint_info_t ep_quirk = {
.epnum = -1,
.out_cables = 0x0007,
.in_cables = 0x0007
};
......
......@@ -165,7 +165,7 @@ struct snd_usb_audio_quirk {
/* data for QUIRK_MIDI_FIXED_ENDPOINT */
struct snd_usb_midi_endpoint_info {
int16_t epnum; /* ep number, -1 autodetect */
int8_t out_ep, in_ep; /* ep number, 0 autodetect */
uint16_t out_cables; /* bitmask */
uint16_t in_cables; /* bitmask */
};
......
......@@ -579,9 +579,9 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
return -ENOMEM;
}
if (int_epd)
pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->epnum);
pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep);
else
pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->epnum);
pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
length = usb_maxpacket(umidi->chip->dev, pipe, 0);
buffer = kmalloc(length, GFP_KERNEL);
if (!buffer) {
......@@ -652,7 +652,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
snd_usbmidi_out_endpoint_delete(ep);
return -ENOMEM;
}
pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->epnum);
pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1) & ~3;
buffer = kmalloc(ep->max_transfer, GFP_KERNEL);
if (!buffer) {
......@@ -737,8 +737,6 @@ static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
int out_ports = 0, in_ports = 0;
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
if (!endpoints[i].epnum)
continue;
if (endpoints[i].out_cables) {
err = snd_usbmidi_out_endpoint_create(umidi, &endpoints[i],
&umidi->endpoints[i]);
......@@ -812,50 +810,64 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT ||
ms_ep->bDescriptorSubtype != MS_GENERAL)
continue;
if (endpoints[epidx].epnum != 0 &&
endpoints[epidx].epnum != (ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) {
++epidx;
if (epidx >= MIDI_MAX_ENDPOINTS) {
printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
break;
if ((ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) == USB_DIR_OUT) {
if (endpoints[epidx].out_ep) {
if (++epidx >= MIDI_MAX_ENDPOINTS) {
printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
break;
}
}
}
endpoints[epidx].epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if (ep->bEndpointAddress & USB_DIR_IN) {
endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
} else {
endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
printk(KERN_INFO "snd-usb-midi: EP %02X: %d jack(s)\n",
ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
} else {
if (endpoints[epidx].in_ep) {
if (++epidx >= MIDI_MAX_ENDPOINTS) {
printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
break;
}
}
endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
printk(KERN_INFO "snd-usb-midi: EP %02X: %d jack(s)\n",
ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
}
printk(KERN_INFO "snd-usb-midi: detected %d %s jack(s) on endpoint %d\n",
ms_ep->bNumEmbMIDIJack,
ep->bEndpointAddress & USB_DIR_IN ? "input" : "output",
endpoints[epidx].epnum);
}
return 0;
}
/*
* If the first endpoint isn't specified, use the first endpoint in the
* If the endpoints aren't specified, use the first bulk endpoints in the
* first alternate setting of the interface.
*/
static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* endpoint)
snd_usb_midi_endpoint_info_t* endpoint)
{
struct usb_interface* intf;
struct usb_host_interface *hostif;
struct usb_interface_descriptor* intfd;
struct usb_endpoint_descriptor* epd;
int i;
if (endpoint->epnum == -1) {
intf = umidi->iface;
if (!intf || intf->num_altsetting < 1)
return -ENOENT;
hostif = intf->altsetting;
intfd = get_iface_desc(hostif);
if (intfd->bNumEndpoints < 1)
return -ENOENT;
epd = get_endpoint(hostif, 0);
endpoint->epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
intf = umidi->iface;
if (!intf || intf->num_altsetting < 1)
return -ENOENT;
hostif = intf->altsetting;
intfd = get_iface_desc(hostif);
if (intfd->bNumEndpoints < 1)
return -ENOENT;
for (i = 0; i < intfd->bNumEndpoints; ++i) {
epd = get_endpoint(hostif, i);
if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
continue;
if (!endpoint->out_ep && endpoint->out_cables &&
(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
endpoint->out_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if (!endpoint->in_ep && endpoint->in_cables &&
(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
endpoint->in_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
return 0;
}
......@@ -892,7 +904,6 @@ static int snd_usbmidi_detect_yamaha(snd_usb_midi_t* umidi,
if (!endpoint->in_cables && !endpoint->out_cables)
return -ENOENT;
endpoint->epnum = -1;
return snd_usbmidi_detect_endpoint(umidi, endpoint);
}
......@@ -940,13 +951,13 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi,
}
}
ep_info.epnum = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.out_cables = endpoint->out_cables & 0x5555;
err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0)
return err;
ep_info.epnum = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.in_ep = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.in_cables = endpoint->in_cables;
err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0)
......@@ -954,7 +965,7 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi,
umidi->endpoints[0].in->urb->complete = snd_usb_complete_callback(snd_usbmidi_in_midiman_complete);
if (endpoint->out_cables > 0x0001) {
ep_info.epnum = get_endpoint(hostif, 4)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.out_ep = get_endpoint(hostif, 4)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.out_cables = endpoint->out_cables & 0xaaaa;
err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[1]);
if (err < 0)
......
......@@ -245,7 +245,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x000f,
.in_cables = 0x000f
}
......@@ -259,7 +258,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x003f,
.in_cables = 0x003f
}
......@@ -273,7 +271,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0003
}
......@@ -287,7 +284,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0003
}
......@@ -301,7 +297,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0013,
.in_cables = 0x0013
}
......@@ -315,7 +310,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0001,
.in_cables = 0x0001
}
......@@ -329,7 +323,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0001,
.in_cables = 0x0001
}
......@@ -343,7 +336,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0013,
.in_cables = 0x0013
}
......@@ -357,7 +349,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0007,
.in_cables = 0x0007
}
......@@ -371,7 +362,6 @@
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0001,
.in_cables = 0x0001
}
......@@ -385,7 +375,6 @@
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x01ff,
.in_cables = 0x01ff
}
......@@ -399,7 +388,6 @@
.ifnum = 2,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x000f,
.in_cables = 0x000f
}
......@@ -413,7 +401,6 @@
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x003f,
.in_cables = 0x003f
}
......@@ -427,7 +414,6 @@
.ifnum = 3,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0001,
.in_cables = 0x0001
}
......@@ -441,7 +427,6 @@
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0007
}
......@@ -455,7 +440,6 @@
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x000f,
.in_cables = 0x000f
}
......@@ -469,7 +453,6 @@
.ifnum = 3,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0003
}
......@@ -483,7 +466,6 @@
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1,
.out_cables = 0x0003,
.in_cables = 0x0007
}
......
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