mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-18 15:44:02 +08:00
Merge branch 'topic/misc' into for-linus
This commit is contained in:
commit
57648cd52b
@ -195,6 +195,24 @@ config RADIO_MAESTRO
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-maestro.
|
||||
|
||||
config RADIO_MIROPCM20
|
||||
tristate "miroSOUND PCM20 radio"
|
||||
depends on ISA && VIDEO_V4L2
|
||||
select SND_MIRO
|
||||
---help---
|
||||
Choose Y here if you have this FM radio card. You also need to enable
|
||||
the ALSA sound system. This choice automatically selects the ALSA
|
||||
sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this
|
||||
is required for the radio-miropcm20.
|
||||
|
||||
In order to control your radio card, you will need to use programs
|
||||
that are compatible with the Video For Linux API. Information on
|
||||
this API and pointers to "v4l" programs may be found at
|
||||
<file:Documentation/video4linux/API.html>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-miropcm20.
|
||||
|
||||
config RADIO_SF16FMI
|
||||
tristate "SF16FMI Radio"
|
||||
depends on ISA && VIDEO_V4L2
|
||||
|
@ -18,6 +18,7 @@ obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
|
||||
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
|
||||
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
|
||||
obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
|
||||
obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
|
||||
obj-$(CONFIG_USB_DSBR) += dsbr100.o
|
||||
obj-$(CONFIG_RADIO_SI470X) += si470x/
|
||||
obj-$(CONFIG_USB_MR800) += radio-mr800.o
|
||||
|
270
drivers/media/radio/radio-miropcm20.c
Normal file
270
drivers/media/radio/radio-miropcm20.c
Normal file
@ -0,0 +1,270 @@
|
||||
/* Miro PCM20 radio driver for Linux radio support
|
||||
* (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
|
||||
* Thanks to Norberto Pellici for the ACI device interface specification
|
||||
* The API part is based on the radiotrack driver by M. Kirkwood
|
||||
* This driver relies on the aci mixer provided by the snd-miro
|
||||
* ALSA driver.
|
||||
* Look there for further info...
|
||||
*/
|
||||
|
||||
/* What ever you think about the ACI, version 0x07 is not very well!
|
||||
* I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
|
||||
* conditions... Robert
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <sound/aci.h>
|
||||
|
||||
static int radio_nr = -1;
|
||||
module_param(radio_nr, int, 0);
|
||||
MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
|
||||
|
||||
static int mono;
|
||||
module_param(mono, bool, 0);
|
||||
MODULE_PARM_DESC(mono, "Force tuner into mono mode.");
|
||||
|
||||
struct pcm20 {
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct video_device vdev;
|
||||
unsigned long freq;
|
||||
int muted;
|
||||
struct snd_miro_aci *aci;
|
||||
};
|
||||
|
||||
static struct pcm20 pcm20_card = {
|
||||
.freq = 87*16000,
|
||||
.muted = 1,
|
||||
};
|
||||
|
||||
static int pcm20_mute(struct pcm20 *dev, unsigned char mute)
|
||||
{
|
||||
dev->muted = mute;
|
||||
return snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, mute, -1);
|
||||
}
|
||||
|
||||
static int pcm20_stereo(struct pcm20 *dev, unsigned char stereo)
|
||||
{
|
||||
return snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, !stereo, -1);
|
||||
}
|
||||
|
||||
static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
|
||||
{
|
||||
unsigned char freql;
|
||||
unsigned char freqh;
|
||||
struct snd_miro_aci *aci = dev->aci;
|
||||
|
||||
dev->freq = freq;
|
||||
|
||||
freq /= 160;
|
||||
if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0))
|
||||
freq /= 10; /* I don't know exactly which version
|
||||
* needs this hack */
|
||||
freql = freq & 0xff;
|
||||
freqh = freq >> 8;
|
||||
|
||||
pcm20_stereo(dev, !mono);
|
||||
return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh);
|
||||
}
|
||||
|
||||
static const struct v4l2_file_operations pcm20_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = video_ioctl2,
|
||||
};
|
||||
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "Miro PCM20", sizeof(v->driver));
|
||||
strlcpy(v->card, "Miro PCM20", sizeof(v->card));
|
||||
strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
|
||||
v->version = 0x1;
|
||||
v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index) /* Only 1 tuner */
|
||||
return -EINVAL;
|
||||
strlcpy(v->name, "FM", sizeof(v->name));
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = 87*16000;
|
||||
v->rangehigh = 108*16000;
|
||||
v->signal = 0xffff;
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return v->index ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct pcm20 *dev = video_drvdata(file);
|
||||
|
||||
if (f->tuner != 0)
|
||||
return -EINVAL;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = dev->freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct pcm20 *dev = video_drvdata(file);
|
||||
|
||||
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
|
||||
return -EINVAL;
|
||||
|
||||
dev->freq = f->frequency;
|
||||
pcm20_setfreq(dev, f->frequency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
switch (qc->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct pcm20 *dev = video_drvdata(file);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = dev->muted;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct pcm20 *dev = video_drvdata(file);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
pcm20_mute(dev, ctrl->value);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
return i ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
a->index = 0;
|
||||
strlcpy(a->name, "Radio", sizeof(a->name));
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
return a->index ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
};
|
||||
|
||||
static int __init pcm20_init(void)
|
||||
{
|
||||
struct pcm20 *dev = &pcm20_card;
|
||||
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
|
||||
int res;
|
||||
|
||||
dev->aci = snd_aci_get_aci();
|
||||
if (dev->aci == NULL) {
|
||||
v4l2_err(v4l2_dev,
|
||||
"you must load the snd-miro driver first!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
|
||||
|
||||
|
||||
res = v4l2_device_register(NULL, v4l2_dev);
|
||||
if (res < 0) {
|
||||
v4l2_err(v4l2_dev, "could not register v4l2_device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
|
||||
dev->vdev.v4l2_dev = v4l2_dev;
|
||||
dev->vdev.fops = &pcm20_fops;
|
||||
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
|
||||
dev->vdev.release = video_device_release_empty;
|
||||
video_set_drvdata(&dev->vdev, dev);
|
||||
|
||||
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
|
||||
goto fail;
|
||||
|
||||
v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n");
|
||||
return 0;
|
||||
fail:
|
||||
v4l2_device_unregister(v4l2_dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt");
|
||||
MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static void __exit pcm20_cleanup(void)
|
||||
{
|
||||
struct pcm20 *dev = &pcm20_card;
|
||||
|
||||
video_unregister_device(&dev->vdev);
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
}
|
||||
|
||||
module_init(pcm20_init);
|
||||
module_exit(pcm20_cleanup);
|
@ -1,5 +1,5 @@
|
||||
#ifndef _MIRO_H_
|
||||
#define _MIRO_H_
|
||||
#ifndef _ACI_H_
|
||||
#define _ACI_H_
|
||||
|
||||
#define ACI_REG_COMMAND 0 /* write register offset */
|
||||
#define ACI_REG_STATUS 1 /* read register offset */
|
||||
@ -70,4 +70,21 @@
|
||||
#define ACI_SET_EQ6 0x45
|
||||
#define ACI_SET_EQ7 0x46 /* ... to Treble */
|
||||
|
||||
#endif /* _MIRO_H_ */
|
||||
struct snd_miro_aci {
|
||||
unsigned long aci_port;
|
||||
int aci_vendor;
|
||||
int aci_product;
|
||||
int aci_version;
|
||||
int aci_amp;
|
||||
int aci_preamp;
|
||||
int aci_solomode;
|
||||
|
||||
struct mutex aci_mutex;
|
||||
};
|
||||
|
||||
int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3);
|
||||
|
||||
struct snd_miro_aci *snd_aci_get_aci(void);
|
||||
|
||||
#endif /* _ACI_H_ */
|
||||
|
@ -70,7 +70,6 @@
|
||||
#define AD1845_PWR_DOWN 0x1b /* power down control */
|
||||
#define CS4235_LEFT_MASTER 0x1b /* left master output control */
|
||||
#define CS4231_REC_FORMAT 0x1c /* clock and data format - record - bits 7-0 MCE */
|
||||
#define CS4231_PLY_VAR_FREQ 0x1d /* playback variable frequency */
|
||||
#define AD1845_CLOCK 0x1d /* crystal clock select and total power down */
|
||||
#define CS4235_RIGHT_MASTER 0x1d /* right master output control */
|
||||
#define CS4231_REC_UPR_CNT 0x1e /* record upper count */
|
||||
|
@ -154,7 +154,6 @@ int snd_wss_create(struct snd_card *card,
|
||||
unsigned short hardware,
|
||||
unsigned short hwshare,
|
||||
struct snd_wss **rchip);
|
||||
int snd_wss_free(struct snd_wss *chip);
|
||||
int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
|
||||
int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
|
||||
int snd_wss_mixer(struct snd_wss *chip);
|
||||
|
@ -58,7 +58,7 @@ config SOUND_OSS_CORE_PRECLAIM
|
||||
Please read Documentation/feature-removal-schedule.txt for
|
||||
details.
|
||||
|
||||
If unusre, say Y.
|
||||
If unsure, say Y.
|
||||
|
||||
source "sound/oss/dmasound/Kconfig"
|
||||
|
||||
|
@ -18,10 +18,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/amba/bus.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/sizes.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
@ -513,15 +510,9 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
|
||||
params_channels(params),
|
||||
aacirun->pcm->r[0].slots);
|
||||
else
|
||||
err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
|
||||
params_channels(params),
|
||||
aacirun->pcm->r[0].slots);
|
||||
|
||||
err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
|
||||
params_channels(params),
|
||||
aacirun->pcm->r[0].slots);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -537,7 +528,7 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
struct aaci_runtime *aacirun = runtime->private_data;
|
||||
|
||||
aacirun->start = (void *)runtime->dma_area;
|
||||
aacirun->end = aacirun->start + runtime->dma_bytes;
|
||||
aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream);
|
||||
aacirun->ptr = aacirun->start;
|
||||
aacirun->period =
|
||||
aacirun->bytes = frames_to_bytes(runtime, runtime->period_size);
|
||||
|
@ -1119,7 +1119,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
||||
goto __kctl_end;
|
||||
}
|
||||
if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
|
||||
if (file && vd->owner != NULL && vd->owner != file) {
|
||||
if (vd->owner != NULL && vd->owner != file) {
|
||||
err = -EPERM;
|
||||
goto __kctl_end;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitrev.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
@ -55,18 +56,6 @@ struct cs8427 {
|
||||
struct cs8427_stream capture;
|
||||
};
|
||||
|
||||
static unsigned char swapbits(unsigned char val)
|
||||
{
|
||||
int bit;
|
||||
unsigned char res = 0;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
res <<= 1;
|
||||
res |= val & 1;
|
||||
val >>= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg,
|
||||
unsigned char val)
|
||||
{
|
||||
@ -149,7 +138,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
|
||||
}
|
||||
data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF;
|
||||
for (idx = 0; idx < count; idx++)
|
||||
data[idx + 1] = swapbits(ndata[idx]);
|
||||
data[idx + 1] = bitrev8(ndata[idx]);
|
||||
if (snd_i2c_sendbytes(device, data, count + 1) != count + 1)
|
||||
return -EIO;
|
||||
return 1;
|
||||
|
@ -225,7 +225,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (tea->ops->mute) {
|
||||
tea->ops->mute(tea, ctrl->value);
|
||||
tea->mute = 1;
|
||||
tea->mute = ctrl->value;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -394,21 +394,15 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
err = snd_wss_create(card, port[dev], cport[dev],
|
||||
err = snd_cs4236_create(card, port[dev], cport[dev],
|
||||
irq[dev],
|
||||
dma1[dev], dma2[dev],
|
||||
WSS_HW_DETECT3, 0, &chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
acard->chip = chip;
|
||||
if (chip->hardware & WSS_HW_CS4236B_MASK) {
|
||||
snd_wss_free(chip);
|
||||
err = snd_cs4236_create(card,
|
||||
port[dev], cport[dev],
|
||||
irq[dev], dma1[dev], dma2[dev],
|
||||
WSS_HW_DETECT, 0, &chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
acard->chip = chip;
|
||||
|
||||
err = snd_cs4236_pcm(chip, 0, &pcm);
|
||||
if (err < 0)
|
||||
@ -418,7 +412,6 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
acard->chip = chip;
|
||||
err = snd_wss_pcm(chip, 0, &pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -87,6 +87,8 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/wss.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
/*
|
||||
*
|
||||
@ -264,7 +266,10 @@ static void snd_cs4236_resume(struct snd_wss *chip)
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*
|
||||
* This function does no fail if the chip is not CS4236B or compatible.
|
||||
* It just an equivalent to the snd_wss_create() then.
|
||||
*/
|
||||
int snd_cs4236_create(struct snd_card *card,
|
||||
unsigned long port,
|
||||
unsigned long cport,
|
||||
@ -281,21 +286,17 @@ int snd_cs4236_create(struct snd_card *card,
|
||||
*rchip = NULL;
|
||||
if (hardware == WSS_HW_DETECT)
|
||||
hardware = WSS_HW_DETECT3;
|
||||
if (cport < 0x100) {
|
||||
snd_printk(KERN_ERR "please, specify control port "
|
||||
"for CS4236+ chips\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = snd_wss_create(card, port, cport,
|
||||
irq, dma1, dma2, hardware, hwshare, &chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
|
||||
snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers "
|
||||
"not available, hardware=0x%x\n", chip->hardware);
|
||||
snd_device_free(card, chip);
|
||||
return -ENODEV;
|
||||
if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
|
||||
snd_printd("chip is not CS4236+, hardware=0x%x\n",
|
||||
chip->hardware);
|
||||
*rchip = chip;
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
@ -308,9 +309,16 @@ int snd_cs4236_create(struct snd_card *card,
|
||||
idx, snd_cs4236_ctrl_in(chip, idx));
|
||||
}
|
||||
#endif
|
||||
if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
|
||||
snd_printk(KERN_ERR "please, specify control port "
|
||||
"for CS4236+ chips\n");
|
||||
snd_device_free(card, chip);
|
||||
return -ENODEV;
|
||||
}
|
||||
ver1 = snd_cs4236_ctrl_in(chip, 1);
|
||||
ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
|
||||
snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
|
||||
snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
|
||||
cport, ver1, ver2);
|
||||
if (ver1 != ver2) {
|
||||
snd_printk(KERN_ERR "CS4236+ chip detected, but "
|
||||
"control port 0x%lx is not valid\n", cport);
|
||||
@ -321,13 +329,17 @@ int snd_cs4236_create(struct snd_card *card,
|
||||
snd_cs4236_ctrl_out(chip, 2, 0xff);
|
||||
snd_cs4236_ctrl_out(chip, 3, 0x00);
|
||||
snd_cs4236_ctrl_out(chip, 4, 0x80);
|
||||
snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE);
|
||||
reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
|
||||
IEC958_AES0_CON_EMPHASIS_NONE;
|
||||
snd_cs4236_ctrl_out(chip, 5, reg);
|
||||
snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
|
||||
snd_cs4236_ctrl_out(chip, 7, 0x00);
|
||||
/* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */
|
||||
/* is working with this setup, other hardware should have */
|
||||
/* different signal paths and this value should be selectable */
|
||||
/* in the future */
|
||||
/*
|
||||
* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
|
||||
* output is working with this setup, other hardware should
|
||||
* have different signal paths and this value should be
|
||||
* selectable in the future
|
||||
*/
|
||||
snd_cs4236_ctrl_out(chip, 8, 0x8c);
|
||||
chip->rate_constraint = snd_cs4236_xrate;
|
||||
chip->set_playback_format = snd_cs4236_playback_format;
|
||||
@ -339,9 +351,10 @@ int snd_cs4236_create(struct snd_card *card,
|
||||
|
||||
/* initialize extended registers */
|
||||
for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
|
||||
snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]);
|
||||
snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
|
||||
snd_cs4236_ext_map[reg]);
|
||||
|
||||
/* initialize compatible but more featured registers */
|
||||
/* initialize compatible but more featured registers */
|
||||
snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
|
||||
snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
|
||||
snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
|
||||
@ -387,6 +400,14 @@ int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
|
||||
.get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
|
||||
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
|
||||
|
||||
#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_single, \
|
||||
.get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
|
||||
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
int mask = (kcontrol->private_value >> 16) & 0xff;
|
||||
@ -490,6 +511,16 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
|
||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
|
||||
|
||||
#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \
|
||||
shift_right, mask, invert, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
|
||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
|
||||
(shift_right << 19) | (mask << 24) | (invert << 22), \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
int mask = (kcontrol->private_value >> 24) & 0xff;
|
||||
@ -560,12 +591,23 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||||
return change;
|
||||
}
|
||||
|
||||
#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
|
||||
#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \
|
||||
shift_right, mask, invert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
|
||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
|
||||
|
||||
#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \
|
||||
shift_right, mask, invert, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
|
||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
|
||||
(shift_right << 19) | (mask << 24) | (invert << 22), \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
|
||||
@ -619,16 +661,18 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||
return change;
|
||||
}
|
||||
|
||||
#define CS4236_MASTER_DIGITAL(xname, xindex) \
|
||||
#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
|
||||
.private_value = 71 << 24 }
|
||||
.private_value = 71 << 24, \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
|
||||
{
|
||||
return (vol < 64) ? 63 - vol : 64 + (71 - vol);
|
||||
}
|
||||
}
|
||||
|
||||
static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
@ -661,11 +705,13 @@ static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct s
|
||||
return change;
|
||||
}
|
||||
|
||||
#define CS4235_OUTPUT_ACCU(xname, xindex) \
|
||||
#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
|
||||
.private_value = 3 << 24 }
|
||||
.private_value = 3 << 24, \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
|
||||
{
|
||||
@ -720,41 +766,56 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_
|
||||
return change;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_cs4236_controls[] = {
|
||||
|
||||
CS4236_DOUBLE("Master Digital Playback Switch", 0,
|
||||
CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Master Digital Capture Switch", 0,
|
||||
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
|
||||
CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
|
||||
CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit),
|
||||
|
||||
CS4236_DOUBLE("Capture Boost Volume", 0,
|
||||
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
|
||||
CS4236_DOUBLE_TLV("Capture Boost Volume", 0,
|
||||
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
|
||||
db_scale_2bit),
|
||||
|
||||
WSS_DOUBLE("PCM Playback Switch", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("PCM Playback Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
|
||||
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
|
||||
CS4236_DOUBLE("DSP Playback Switch", 0,
|
||||
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("DSP Playback Volume", 0,
|
||||
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
|
||||
CS4236_DOUBLE_TLV("DSP Playback Volume", 0,
|
||||
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
|
||||
CS4236_DOUBLE("FM Playback Switch", 0,
|
||||
CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("FM Playback Volume", 0,
|
||||
CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
|
||||
CS4236_DOUBLE_TLV("FM Playback Volume", 0,
|
||||
CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
|
||||
CS4236_DOUBLE("Wavetable Playback Switch", 0,
|
||||
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Wavetable Playback Volume", 0,
|
||||
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
|
||||
CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0,
|
||||
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1,
|
||||
db_scale_6bit_12db_max),
|
||||
|
||||
WSS_DOUBLE("Synth Playback Switch", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Synth Volume", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Synth Volume", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE("Synth Capture Switch", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Synth Capture Bypass", 0,
|
||||
@ -764,14 +825,16 @@ CS4236_DOUBLE("Mic Playback Switch", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
|
||||
CS4236_DOUBLE("Mic Capture Switch", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
|
||||
CS4236_DOUBLE("Mic Playback Boost", 0,
|
||||
CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC,
|
||||
0, 0, 31, 1, db_scale_5bit_22db_max),
|
||||
CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
|
||||
|
||||
WSS_DOUBLE("Line Playback Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Line Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Line Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE("Line Capture Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Line Capture Bypass", 0,
|
||||
@ -779,57 +842,63 @@ WSS_DOUBLE("Line Capture Bypass", 0,
|
||||
|
||||
WSS_DOUBLE("CD Playback Switch", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("CD Volume", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("CD Volume", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE("CD Capture Switch", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
|
||||
|
||||
CS4236_DOUBLE1("Mono Output Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
|
||||
CS4236_DOUBLE1("Mono Playback Switch", 0,
|
||||
CS4236_DOUBLE1("Beep Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
|
||||
WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
|
||||
WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
|
||||
WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1,
|
||||
db_scale_4bit),
|
||||
WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0),
|
||||
|
||||
WSS_DOUBLE("Capture Volume", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
|
||||
WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
|
||||
0, 0, 15, 0, db_scale_rec_gain),
|
||||
WSS_DOUBLE("Analog Loopback Capture Switch", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
|
||||
|
||||
WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
|
||||
CS4236_DOUBLE1("Digital Loopback Playback Volume", 0,
|
||||
CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
|
||||
WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
|
||||
CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0,
|
||||
CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_cs4235_controls[] = {
|
||||
|
||||
WSS_DOUBLE("Master Switch", 0,
|
||||
WSS_DOUBLE("Master Playback Switch", 0,
|
||||
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Master Volume", 0,
|
||||
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Master Playback Volume", 0,
|
||||
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1,
|
||||
db_scale_5bit_6db_max),
|
||||
|
||||
CS4235_OUTPUT_ACCU("Playback Volume", 0),
|
||||
CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max),
|
||||
|
||||
CS4236_DOUBLE("Master Digital Playback Switch", 0,
|
||||
CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Master Digital Capture Switch", 0,
|
||||
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
|
||||
CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
|
||||
|
||||
WSS_DOUBLE("Master Digital Playback Switch", 1,
|
||||
WSS_DOUBLE("Synth Playback Switch", 1,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Master Digital Capture Switch", 1,
|
||||
WSS_DOUBLE("Synth Capture Switch", 1,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Master Digital Volume", 1,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Synth Volume", 1,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
|
||||
CS4236_DOUBLE("Capture Volume", 0,
|
||||
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
|
||||
CS4236_DOUBLE_TLV("Capture Volume", 0,
|
||||
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
|
||||
db_scale_2bit),
|
||||
|
||||
WSS_DOUBLE("PCM Switch", 0,
|
||||
WSS_DOUBLE("PCM Playback Switch", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("PCM Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
|
||||
WSS_DOUBLE("PCM Capture Switch", 0,
|
||||
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
|
||||
WSS_DOUBLE_TLV("PCM Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
|
||||
CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
|
||||
|
||||
@ -842,29 +911,29 @@ CS4236_DOUBLE("Mic Capture Switch", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Mic Playback Switch", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
|
||||
CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
|
||||
CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0),
|
||||
CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1,
|
||||
db_scale_5bit_22db_max),
|
||||
CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0),
|
||||
|
||||
WSS_DOUBLE("Aux Playback Switch", 0,
|
||||
WSS_DOUBLE("Line Playback Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Aux Capture Switch", 0,
|
||||
WSS_DOUBLE("Line Capture Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Aux Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Line Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
|
||||
WSS_DOUBLE("Aux Playback Switch", 1,
|
||||
WSS_DOUBLE("CD Playback Switch", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Aux Capture Switch", 1,
|
||||
WSS_DOUBLE("CD Capture Switch", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Aux Volume", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("CD Volume", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
|
||||
CS4236_DOUBLE1("Master Mono Switch", 0,
|
||||
CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
|
||||
|
||||
CS4236_DOUBLE1("Mono Switch", 0,
|
||||
CS4236_DOUBLE1("Beep Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
|
||||
WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
|
||||
WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
|
||||
|
||||
WSS_DOUBLE("Analog Loopback Switch", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
|
||||
|
@ -102,8 +102,6 @@
|
||||
|
||||
struct snd_es18xx {
|
||||
unsigned long port; /* port of ESS chip */
|
||||
unsigned long mpu_port; /* MPU-401 port of ESS chip */
|
||||
unsigned long fm_port; /* FM port */
|
||||
unsigned long ctrl_port; /* Control port of ESS chip */
|
||||
struct resource *res_port;
|
||||
struct resource *res_mpu_port;
|
||||
@ -116,8 +114,6 @@ struct snd_es18xx {
|
||||
unsigned short audio2_vol; /* volume level of audio2 */
|
||||
|
||||
unsigned short active; /* active channel mask */
|
||||
unsigned int dma1_size;
|
||||
unsigned int dma2_size;
|
||||
unsigned int dma1_shift;
|
||||
unsigned int dma2_shift;
|
||||
|
||||
@ -135,7 +131,6 @@ struct snd_es18xx {
|
||||
|
||||
spinlock_t reg_lock;
|
||||
spinlock_t mixer_lock;
|
||||
spinlock_t ctrl_lock;
|
||||
#ifdef CONFIG_PM
|
||||
unsigned char pm_reg;
|
||||
#endif
|
||||
@ -354,7 +349,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch
|
||||
}
|
||||
|
||||
|
||||
static int snd_es18xx_reset(struct snd_es18xx *chip)
|
||||
static int __devinit snd_es18xx_reset(struct snd_es18xx *chip)
|
||||
{
|
||||
int i;
|
||||
outb(0x03, chip->port + 0x06);
|
||||
@ -490,8 +485,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip,
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
unsigned int count = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
chip->dma2_size = size;
|
||||
|
||||
snd_es18xx_rate_set(chip, substream, DAC2);
|
||||
|
||||
/* Transfer Count Reload */
|
||||
@ -591,8 +584,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
unsigned int count = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
chip->dma1_size = size;
|
||||
|
||||
snd_es18xx_reset_fifo(chip);
|
||||
|
||||
/* Set stereo/mono */
|
||||
@ -659,8 +650,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip,
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
unsigned int count = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
chip->dma1_size = size;
|
||||
|
||||
snd_es18xx_reset_fifo(chip);
|
||||
|
||||
/* Set stereo/mono */
|
||||
@ -821,17 +810,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
|
||||
static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
int pos;
|
||||
|
||||
if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
|
||||
if (!(chip->active & DAC2))
|
||||
return 0;
|
||||
pos = snd_dma_pointer(chip->dma2, chip->dma2_size);
|
||||
pos = snd_dma_pointer(chip->dma2, size);
|
||||
return pos >> chip->dma2_shift;
|
||||
} else {
|
||||
if (!(chip->active & DAC1))
|
||||
return 0;
|
||||
pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
|
||||
pos = snd_dma_pointer(chip->dma1, size);
|
||||
return pos >> chip->dma1_shift;
|
||||
}
|
||||
}
|
||||
@ -839,11 +829,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s
|
||||
static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
int pos;
|
||||
|
||||
if (!(chip->active & ADC1))
|
||||
return 0;
|
||||
pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
|
||||
pos = snd_dma_pointer(chip->dma1, size);
|
||||
return pos >> chip->dma1_shift;
|
||||
}
|
||||
|
||||
@ -974,9 +965,6 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream)
|
||||
|
||||
static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static char *texts4Source[4] = {
|
||||
"Mic", "CD", "Line", "Master"
|
||||
};
|
||||
static char *texts5Source[5] = {
|
||||
"Mic", "CD", "Line", "Master", "Mix"
|
||||
};
|
||||
@ -994,7 +982,8 @@ static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
|
||||
uinfo->value.enumerated.items = 4;
|
||||
if (uinfo->value.enumerated.item > 3)
|
||||
uinfo->value.enumerated.item = 3;
|
||||
strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]);
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
texts5Source[uinfo->value.enumerated.item]);
|
||||
break;
|
||||
case 0x1887:
|
||||
case 0x1888:
|
||||
@ -1378,11 +1367,9 @@ ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
|
||||
static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
|
||||
{
|
||||
int data;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&chip->ctrl_lock, flags);
|
||||
|
||||
outb(reg, chip->ctrl_port);
|
||||
data = inb(chip->ctrl_port + 1);
|
||||
spin_unlock_irqrestore(&chip->ctrl_lock, flags);
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -1398,7 +1385,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip,
|
||||
#endif
|
||||
}
|
||||
|
||||
static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
|
||||
static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip,
|
||||
unsigned long mpu_port,
|
||||
unsigned long fm_port)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
@ -1412,15 +1401,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
|
||||
if (chip->caps & ES18XX_CONTROL) {
|
||||
/* Hardware volume IRQ */
|
||||
snd_es18xx_config_write(chip, 0x27, chip->irq);
|
||||
if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
|
||||
if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
|
||||
/* FM I/O */
|
||||
snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8);
|
||||
snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff);
|
||||
snd_es18xx_config_write(chip, 0x62, fm_port >> 8);
|
||||
snd_es18xx_config_write(chip, 0x63, fm_port & 0xff);
|
||||
}
|
||||
if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
|
||||
if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
|
||||
/* MPU-401 I/O */
|
||||
snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8);
|
||||
snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff);
|
||||
snd_es18xx_config_write(chip, 0x64, mpu_port >> 8);
|
||||
snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff);
|
||||
/* MPU-401 IRQ */
|
||||
snd_es18xx_config_write(chip, 0x28, chip->irq);
|
||||
}
|
||||
@ -1507,11 +1496,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
|
||||
snd_es18xx_mixer_write(chip, 0x7A, 0x68);
|
||||
/* Enable and set hardware volume interrupt */
|
||||
snd_es18xx_mixer_write(chip, 0x64, 0x06);
|
||||
if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
|
||||
if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
|
||||
/* MPU401 share irq with audio
|
||||
Joystick enabled
|
||||
FM enabled */
|
||||
snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1);
|
||||
snd_es18xx_mixer_write(chip, 0x40,
|
||||
0x43 | (mpu_port & 0xf0) >> 1);
|
||||
}
|
||||
snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01);
|
||||
}
|
||||
@ -1629,7 +1619,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
|
||||
static int __devinit snd_es18xx_probe(struct snd_es18xx *chip,
|
||||
unsigned long mpu_port,
|
||||
unsigned long fm_port)
|
||||
{
|
||||
if (snd_es18xx_identify(chip) < 0) {
|
||||
snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port);
|
||||
@ -1650,8 +1642,6 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
|
||||
chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
|
||||
break;
|
||||
case 0x1887:
|
||||
chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
|
||||
break;
|
||||
case 0x1888:
|
||||
chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
|
||||
break;
|
||||
@ -1666,7 +1656,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
|
||||
if (chip->dma1 == chip->dma2)
|
||||
chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME);
|
||||
|
||||
return snd_es18xx_initialize(chip);
|
||||
return snd_es18xx_initialize(chip, mpu_port, fm_port);
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops snd_es18xx_playback_ops = {
|
||||
@ -1802,10 +1792,7 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card,
|
||||
|
||||
spin_lock_init(&chip->reg_lock);
|
||||
spin_lock_init(&chip->mixer_lock);
|
||||
spin_lock_init(&chip->ctrl_lock);
|
||||
chip->port = port;
|
||||
chip->mpu_port = mpu_port;
|
||||
chip->fm_port = fm_port;
|
||||
chip->irq = -1;
|
||||
chip->dma1 = -1;
|
||||
chip->dma2 = -1;
|
||||
@ -1841,11 +1828,11 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card,
|
||||
}
|
||||
chip->dma2 = dma2;
|
||||
|
||||
if (snd_es18xx_probe(chip) < 0) {
|
||||
if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) {
|
||||
snd_es18xx_free(card);
|
||||
return -ENODEV;
|
||||
}
|
||||
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, NULL, &ops);
|
||||
return -ENODEV;
|
||||
}
|
||||
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
|
||||
if (err < 0) {
|
||||
snd_es18xx_free(card);
|
||||
return err;
|
||||
@ -1980,7 +1967,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
|
||||
#ifdef CONFIG_PNP
|
||||
static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
|
||||
static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
|
||||
#endif
|
||||
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */
|
||||
#ifndef CONFIG_PNP
|
||||
@ -2160,19 +2147,23 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
|
||||
return err;
|
||||
|
||||
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
|
||||
if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) {
|
||||
snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port);
|
||||
if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
|
||||
OPL3_HW_OPL3, 0, &opl3) < 0) {
|
||||
snd_printk(KERN_WARNING PFX
|
||||
"opl3 not detected at 0x%lx\n",
|
||||
fm_port[dev]);
|
||||
} else {
|
||||
if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0)
|
||||
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
|
||||
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
|
||||
chip->mpu_port, 0,
|
||||
irq[dev], 0,
|
||||
&chip->rmidi)) < 0)
|
||||
err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
|
||||
mpu_port[dev], 0,
|
||||
irq[dev], 0, &chip->rmidi);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -141,15 +141,7 @@ struct snd_opti9xx {
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
long wss_base;
|
||||
int irq;
|
||||
int dma1;
|
||||
int dma2;
|
||||
|
||||
long fm_port;
|
||||
|
||||
long mpu_port;
|
||||
int mpu_irq;
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
struct pnp_dev *dev;
|
||||
@ -216,13 +208,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
|
||||
chip->wss_base = -1;
|
||||
chip->irq = -1;
|
||||
chip->dma1 = -1;
|
||||
chip->dma2 = -1;
|
||||
chip->fm_port = -1;
|
||||
chip->mpu_port = -1;
|
||||
chip->mpu_irq = -1;
|
||||
|
||||
switch (hardware) {
|
||||
#ifndef OPTi93X
|
||||
@ -348,7 +334,10 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
|
||||
(snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask)))
|
||||
|
||||
|
||||
static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
|
||||
static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
|
||||
long wss_base,
|
||||
int irq, int dma1, int dma2,
|
||||
long mpu_port, int mpu_irq)
|
||||
{
|
||||
unsigned char wss_base_bits;
|
||||
unsigned char irq_bits;
|
||||
@ -416,7 +405,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (chip->wss_base) {
|
||||
switch (wss_base) {
|
||||
case 0x530:
|
||||
wss_base_bits = 0x00;
|
||||
break;
|
||||
@ -430,14 +419,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
|
||||
wss_base_bits = 0x02;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n",
|
||||
chip->wss_base);
|
||||
snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base);
|
||||
goto __skip_base;
|
||||
}
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
|
||||
|
||||
__skip_base:
|
||||
switch (chip->irq) {
|
||||
switch (irq) {
|
||||
//#ifdef OPTi93X
|
||||
case 5:
|
||||
irq_bits = 0x05;
|
||||
@ -456,11 +444,11 @@ __skip_base:
|
||||
irq_bits = 0x04;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq);
|
||||
snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq);
|
||||
goto __skip_resources;
|
||||
}
|
||||
|
||||
switch (chip->dma1) {
|
||||
switch (dma1) {
|
||||
case 0:
|
||||
dma_bits = 0x01;
|
||||
break;
|
||||
@ -471,38 +459,36 @@ __skip_base:
|
||||
dma_bits = 0x03;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n",
|
||||
chip->dma1);
|
||||
snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1);
|
||||
goto __skip_resources;
|
||||
}
|
||||
|
||||
#if defined(CS4231) || defined(OPTi93X)
|
||||
if (chip->dma1 == chip->dma2) {
|
||||
if (dma1 == dma2) {
|
||||
snd_printk(KERN_ERR "don't want to share dmas\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
switch (chip->dma2) {
|
||||
switch (dma2) {
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n",
|
||||
chip->dma2);
|
||||
snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2);
|
||||
goto __skip_resources;
|
||||
}
|
||||
dma_bits |= 0x04;
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
#ifndef OPTi93X
|
||||
outb(irq_bits << 3 | dma_bits, chip->wss_base);
|
||||
outb(irq_bits << 3 | dma_bits, wss_base);
|
||||
#else /* OPTi93X */
|
||||
snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
|
||||
#endif /* OPTi93X */
|
||||
|
||||
__skip_resources:
|
||||
if (chip->hardware > OPTi9XX_HW_82C928) {
|
||||
switch (chip->mpu_port) {
|
||||
switch (mpu_port) {
|
||||
case 0:
|
||||
case -1:
|
||||
break;
|
||||
@ -520,12 +506,11 @@ __skip_resources:
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING
|
||||
"MPU-401 port 0x%lx not valid\n",
|
||||
chip->mpu_port);
|
||||
"MPU-401 port 0x%lx not valid\n", mpu_port);
|
||||
goto __skip_mpu;
|
||||
}
|
||||
|
||||
switch (chip->mpu_irq) {
|
||||
switch (mpu_irq) {
|
||||
case 5:
|
||||
mpu_irq_bits = 0x02;
|
||||
break;
|
||||
@ -540,12 +525,12 @@ __skip_resources:
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
|
||||
chip->mpu_irq);
|
||||
mpu_irq);
|
||||
goto __skip_mpu;
|
||||
}
|
||||
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6),
|
||||
(chip->mpu_port <= 0) ? 0x00 :
|
||||
(mpu_port <= 0) ? 0x00 :
|
||||
0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3,
|
||||
0xf8);
|
||||
}
|
||||
@ -701,6 +686,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
{
|
||||
static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
|
||||
int error;
|
||||
int xdma2;
|
||||
struct snd_opti9xx *chip = card->private_data;
|
||||
struct snd_wss *codec;
|
||||
#ifdef CS4231
|
||||
@ -715,31 +701,25 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
"OPTi9xx MC")) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->wss_base = port;
|
||||
chip->fm_port = fm_port;
|
||||
chip->mpu_port = mpu_port;
|
||||
chip->irq = irq;
|
||||
chip->mpu_irq = mpu_irq;
|
||||
chip->dma1 = dma1;
|
||||
#if defined(CS4231) || defined(OPTi93X)
|
||||
chip->dma2 = dma2;
|
||||
xdma2 = dma2;
|
||||
#else
|
||||
chip->dma2 = -1;
|
||||
xdma2 = -1;
|
||||
#endif
|
||||
|
||||
if (chip->wss_base == SNDRV_AUTO_PORT) {
|
||||
chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4);
|
||||
if (chip->wss_base < 0) {
|
||||
if (port == SNDRV_AUTO_PORT) {
|
||||
port = snd_legacy_find_free_ioport(possible_ports, 4);
|
||||
if (port < 0) {
|
||||
snd_printk(KERN_ERR "unable to find a free WSS port\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
error = snd_opti9xx_configure(chip);
|
||||
error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2,
|
||||
mpu_port, mpu_irq);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = snd_wss_create(card, chip->wss_base + 4, -1,
|
||||
chip->irq, chip->dma1, chip->dma2,
|
||||
error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2,
|
||||
#ifdef OPTi93X
|
||||
WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
|
||||
#else
|
||||
@ -763,35 +743,35 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
return error;
|
||||
#endif
|
||||
#ifdef OPTi93X
|
||||
error = request_irq(chip->irq, snd_opti93x_interrupt,
|
||||
error = request_irq(irq, snd_opti93x_interrupt,
|
||||
IRQF_DISABLED, DEV_NAME" - WSS", codec);
|
||||
if (error < 0) {
|
||||
snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
chip->irq = irq;
|
||||
strcpy(card->driver, chip->name);
|
||||
sprintf(card->shortname, "OPTi %s", card->driver);
|
||||
#if defined(CS4231) || defined(OPTi93X)
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
|
||||
card->shortname, pcm->name, chip->wss_base + 4,
|
||||
chip->irq, chip->dma1, chip->dma2);
|
||||
card->shortname, pcm->name, port + 4, irq, dma1, xdma2);
|
||||
#else
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
|
||||
card->shortname, pcm->name, chip->wss_base + 4,
|
||||
chip->irq, chip->dma1);
|
||||
card->shortname, pcm->name, port + 4, irq, dma1);
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT)
|
||||
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
|
||||
rmidi = NULL;
|
||||
else
|
||||
if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
|
||||
chip->mpu_port, 0, chip->mpu_irq, IRQF_DISABLED,
|
||||
&rmidi)))
|
||||
else {
|
||||
error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
|
||||
mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi);
|
||||
if (error)
|
||||
snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
|
||||
chip->mpu_port);
|
||||
mpu_port);
|
||||
}
|
||||
|
||||
if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
|
||||
if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
|
||||
struct snd_opl3 *opl3 = NULL;
|
||||
#ifndef OPTi93X
|
||||
if (chip->hardware == OPTi9XX_HW_82C928 ||
|
||||
@ -801,9 +781,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
/* assume we have an OPL4 */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
|
||||
0x20, 0x20);
|
||||
if (snd_opl4_create(card,
|
||||
chip->fm_port,
|
||||
chip->fm_port - 8,
|
||||
if (snd_opl4_create(card, fm_port, fm_port - 8,
|
||||
2, &opl3, &opl4) < 0) {
|
||||
/* no luck, use OPL3 instead */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
|
||||
@ -811,12 +789,10 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
}
|
||||
}
|
||||
#endif /* !OPTi93X */
|
||||
if (!opl3 && snd_opl3_create(card,
|
||||
chip->fm_port,
|
||||
chip->fm_port + 2,
|
||||
if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2,
|
||||
OPL3_HW_AUTO, 0, &opl3) < 0) {
|
||||
snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
|
||||
chip->fm_port, chip->fm_port + 4 - 1);
|
||||
fm_port, fm_port + 4 - 1);
|
||||
}
|
||||
if (opl3) {
|
||||
error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
|
||||
|
@ -1682,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip)
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
int snd_wss_free(struct snd_wss *chip)
|
||||
static int snd_wss_free(struct snd_wss *chip)
|
||||
{
|
||||
release_and_free_resource(chip->res_port);
|
||||
release_and_free_resource(chip->res_cport);
|
||||
@ -1705,7 +1705,6 @@ int snd_wss_free(struct snd_wss *chip)
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_wss_free);
|
||||
|
||||
static int snd_wss_dev_free(struct snd_device *device)
|
||||
{
|
||||
@ -2225,7 +2224,7 @@ WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
|
||||
.get = snd_wss_get_mux,
|
||||
.put = snd_wss_put_mux,
|
||||
},
|
||||
WSS_DOUBLE("Mic Boost", 0,
|
||||
WSS_DOUBLE("Mic Boost (+20dB)", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
|
||||
WSS_SINGLE("Loopback Capture Switch", 0,
|
||||
CS4231_LOOPBACK, 0, 1, 0),
|
||||
@ -2236,14 +2235,14 @@ WSS_DOUBLE("Line Playback Switch", 0,
|
||||
WSS_DOUBLE_TLV("Line Playback Volume", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_SINGLE("Mono Playback Switch", 0,
|
||||
WSS_SINGLE("Beep Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, 7, 1, 1),
|
||||
WSS_SINGLE_TLV("Mono Playback Volume", 0,
|
||||
WSS_SINGLE_TLV("Beep Playback Volume", 0,
|
||||
CS4231_MONO_CTRL, 0, 15, 1,
|
||||
db_scale_4bit),
|
||||
WSS_SINGLE("Mono Output Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, 6, 1, 1),
|
||||
WSS_SINGLE("Mono Output Playback Bypass", 0,
|
||||
WSS_SINGLE("Beep Bypass Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, 5, 1, 0),
|
||||
};
|
||||
|
||||
|
@ -838,7 +838,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg)
|
||||
if ((err = audio_devs[dev]->d->prepare_for_input(dev,
|
||||
dmap_in->fragment_size, dmap_in->nbufs)) < 0) {
|
||||
spin_unlock_irqrestore(&dmap_in->lock,flags);
|
||||
return -err;
|
||||
return err;
|
||||
}
|
||||
dmap_in->dma_mode = DMODE_INPUT;
|
||||
audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT;
|
||||
|
@ -426,7 +426,7 @@ midi_synth_open(int dev, int mode)
|
||||
int err;
|
||||
struct midi_input_info *inc;
|
||||
|
||||
if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL)
|
||||
if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
midi2synth[orig_dev] = dev;
|
||||
|
@ -770,7 +770,7 @@ static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg)
|
||||
|
||||
midi_dev = synth_devs[dev]->midi_dev;
|
||||
|
||||
if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL)
|
||||
if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
devc = &dev_conf[midi_dev];
|
||||
|
@ -570,6 +570,7 @@ config SND_ICE1712
|
||||
tristate "ICEnsemble ICE1712 (Envy24)"
|
||||
select SND_MPU401_UART
|
||||
select SND_AC97_CODEC
|
||||
select BITREVERSE
|
||||
help
|
||||
Say Y here to include support for soundcards based on the
|
||||
ICE1712 (Envy24) chip.
|
||||
|
@ -55,7 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card *
|
||||
* 1 = MediaForte 256-PCS
|
||||
* 2 = MediaForte 256-PCPR
|
||||
* 3 = MediaForte 64-PCR
|
||||
* 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card
|
||||
* 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
|
||||
* High 16-bits are video (radio) device number + 1
|
||||
*/
|
||||
static int tea575x_tuner[SNDRV_CARDS];
|
||||
@ -67,7 +67,10 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
|
||||
module_param_array(tea575x_tuner, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner.");
|
||||
MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only).");
|
||||
|
||||
#define TUNER_ONLY (1<<4)
|
||||
#define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF)
|
||||
|
||||
/*
|
||||
* Direct registers
|
||||
@ -160,7 +163,7 @@ struct fm801 {
|
||||
unsigned int multichannel: 1, /* multichannel support */
|
||||
secondary: 1; /* secondary codec */
|
||||
unsigned char secondary_addr; /* address of the secondary codec */
|
||||
unsigned int tea575x_tuner; /* tuner flags */
|
||||
unsigned int tea575x_tuner; /* tuner access method & flags */
|
||||
|
||||
unsigned short ply_ctrl; /* playback control */
|
||||
unsigned short cap_ctrl; /* capture control */
|
||||
@ -1287,7 +1290,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||
{
|
||||
unsigned short cmdw;
|
||||
|
||||
if (chip->tea575x_tuner & 0x0010)
|
||||
if (chip->tea575x_tuner & TUNER_ONLY)
|
||||
goto __ac97_ok;
|
||||
|
||||
/* codec cold reset + AC'97 warm reset */
|
||||
@ -1296,11 +1299,13 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||
udelay(100);
|
||||
outw(0, FM801_REG(chip, CODEC_CTRL));
|
||||
|
||||
if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) {
|
||||
snd_printk(KERN_ERR "Primary AC'97 codec not found\n");
|
||||
if (! resume)
|
||||
return -EIO;
|
||||
}
|
||||
if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
|
||||
if (!resume) {
|
||||
snd_printk(KERN_INFO "Primary AC'97 codec not found, "
|
||||
"assume SF64-PCR (tuner-only)\n");
|
||||
chip->tea575x_tuner = 3 | TUNER_ONLY;
|
||||
goto __ac97_ok;
|
||||
}
|
||||
|
||||
if (chip->multichannel) {
|
||||
if (chip->secondary_addr) {
|
||||
@ -1414,7 +1419,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||
return err;
|
||||
}
|
||||
chip->port = pci_resource_start(pci, 0);
|
||||
if ((tea575x_tuner & 0x0010) == 0) {
|
||||
if ((tea575x_tuner & TUNER_ONLY) == 0) {
|
||||
if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
|
||||
"FM801", chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
|
||||
@ -1429,6 +1434,14 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||
chip->multichannel = 1;
|
||||
|
||||
snd_fm801_chip_init(chip, 0);
|
||||
/* init might set tuner access method */
|
||||
tea575x_tuner = chip->tea575x_tuner;
|
||||
|
||||
if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
|
||||
pci_clear_master(pci);
|
||||
free_irq(chip->irq, chip);
|
||||
chip->irq = -1;
|
||||
}
|
||||
|
||||
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
|
||||
snd_fm801_free(chip);
|
||||
@ -1438,12 +1451,13 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||
snd_card_set_dev(card, &pci->dev);
|
||||
|
||||
#ifdef TEA575X_RADIO
|
||||
if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) {
|
||||
if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
|
||||
(tea575x_tuner & TUNER_TYPE_MASK) < 4) {
|
||||
chip->tea.dev_nr = tea575x_tuner >> 16;
|
||||
chip->tea.card = card;
|
||||
chip->tea.freq_fixup = 10700;
|
||||
chip->tea.private_data = chip;
|
||||
chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1];
|
||||
chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1];
|
||||
snd_tea575x_init(&chip->tea);
|
||||
}
|
||||
#endif
|
||||
@ -1483,7 +1497,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
|
||||
sprintf(card->longname, "%s at 0x%lx, irq %i",
|
||||
card->shortname, chip->port, chip->irq);
|
||||
|
||||
if (tea575x_tuner[dev] & 0x0010)
|
||||
if (chip->tea575x_tuner & TUNER_ONLY)
|
||||
goto __fm801_tuner_only;
|
||||
|
||||
if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
|
||||
|
@ -503,6 +503,31 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* suspend/resume
|
||||
* */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int juli_resume(struct snd_ice1712 *ice)
|
||||
{
|
||||
struct snd_akm4xxx *ak = ice->akm;
|
||||
struct juli_spec *spec = ice->spec;
|
||||
/* akm4358 un-reset, un-mute */
|
||||
snd_akm4xxx_reset(ak, 0);
|
||||
/* reinit ak4114 */
|
||||
snd_ak4114_reinit(spec->ak4114);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int juli_suspend(struct snd_ice1712 *ice)
|
||||
{
|
||||
struct snd_akm4xxx *ak = ice->akm;
|
||||
/* akm4358 reset and soft-mute */
|
||||
snd_akm4xxx_reset(ak, 1);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* initialize the chip
|
||||
*/
|
||||
@ -646,6 +671,13 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
|
||||
ice->set_spdif_clock = juli_set_spdif_clock;
|
||||
|
||||
ice->spdif.ops.open = juli_spdif_in_open;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
ice->pm_resume = juli_resume;
|
||||
ice->pm_suspend = juli_suspend;
|
||||
ice->pm_suspend_enabled = 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2062,6 +2062,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
|
||||
.name = "MSI P4 ATX 645 Ultra",
|
||||
.type = AC97_TUNE_HP_ONLY
|
||||
},
|
||||
{
|
||||
.subvendor = 0x161f,
|
||||
.subdevice = 0x203a,
|
||||
.name = "Gateway 4525GZ", /* AD1981B */
|
||||
.type = AC97_TUNE_INV_EAPD
|
||||
},
|
||||
{
|
||||
.subvendor = 0x1734,
|
||||
.subdevice = 0x0088,
|
||||
|
@ -2893,7 +2893,9 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
|
||||
if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
|
||||
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
|
||||
altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
|
||||
if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) {
|
||||
int err = snd_usbmidi_create(chip->card, iface,
|
||||
&chip->midi_list, NULL);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
|
||||
continue;
|
||||
}
|
||||
@ -3038,12 +3040,11 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = &uaxx_ep
|
||||
};
|
||||
if (chip->usb_id == USB_ID(0x0582, 0x002b))
|
||||
return snd_usb_create_midi_interface(chip, iface,
|
||||
&ua700_quirk);
|
||||
else
|
||||
return snd_usb_create_midi_interface(chip, iface,
|
||||
&uaxx_quirk);
|
||||
const struct snd_usb_audio_quirk *quirk =
|
||||
chip->usb_id == USB_ID(0x0582, 0x002b)
|
||||
? &ua700_quirk : &uaxx_quirk;
|
||||
return snd_usbmidi_create(chip->card, iface,
|
||||
&chip->midi_list, quirk);
|
||||
}
|
||||
|
||||
if (altsd->bNumEndpoints != 1)
|
||||
@ -3370,6 +3371,13 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
|
||||
return 0; /* keep this altsetting */
|
||||
}
|
||||
|
||||
static int create_any_midi_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_interface *intf,
|
||||
const struct snd_usb_audio_quirk *quirk)
|
||||
{
|
||||
return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk);
|
||||
}
|
||||
|
||||
/*
|
||||
* audio-interface quirks
|
||||
*
|
||||
@ -3387,14 +3395,14 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
|
||||
static const quirk_func_t quirk_funcs[] = {
|
||||
[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
|
||||
[QUIRK_COMPOSITE] = create_composite_quirk,
|
||||
[QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface,
|
||||
[QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface,
|
||||
[QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface,
|
||||
[QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface,
|
||||
[QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface,
|
||||
[QUIRK_MIDI_FASTLANE] = snd_usb_create_midi_interface,
|
||||
[QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface,
|
||||
[QUIRK_MIDI_CME] = snd_usb_create_midi_interface,
|
||||
[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_CME] = create_any_midi_quirk,
|
||||
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
|
||||
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
|
||||
[QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
|
||||
|
@ -132,7 +132,6 @@ struct snd_usb_audio {
|
||||
int pcm_devs;
|
||||
|
||||
struct list_head midi_list; /* list of midi interfaces */
|
||||
int next_midi_device;
|
||||
|
||||
struct list_head mixer_list; /* list of mixer interfaces */
|
||||
};
|
||||
@ -227,8 +226,10 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
|
||||
int ignore_error);
|
||||
void snd_usb_mixer_disconnect(struct list_head *p);
|
||||
|
||||
int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface,
|
||||
const struct snd_usb_audio_quirk *quirk);
|
||||
int snd_usbmidi_create(struct snd_card *card,
|
||||
struct usb_interface *iface,
|
||||
struct list_head *midi_list,
|
||||
const struct snd_usb_audio_quirk *quirk);
|
||||
void snd_usbmidi_input_stop(struct list_head* p);
|
||||
void snd_usbmidi_input_start(struct list_head* p);
|
||||
void snd_usbmidi_disconnect(struct list_head *p);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* usbmidi.c - ALSA USB MIDI driver
|
||||
*
|
||||
* Copyright (c) 2002-2007 Clemens Ladisch
|
||||
* Copyright (c) 2002-2009 Clemens Ladisch
|
||||
* All rights reserved.
|
||||
*
|
||||
* Based on the OSS usb-midi driver by NAGANO Daisuke,
|
||||
@ -47,6 +47,7 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/wait.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include <sound/asequencer.h>
|
||||
#include "usbaudio.h"
|
||||
@ -101,7 +102,8 @@ struct usb_protocol_ops {
|
||||
};
|
||||
|
||||
struct snd_usb_midi {
|
||||
struct snd_usb_audio *chip;
|
||||
struct usb_device *dev;
|
||||
struct snd_card *card;
|
||||
struct usb_interface *iface;
|
||||
const struct snd_usb_audio_quirk *quirk;
|
||||
struct snd_rawmidi *rmidi;
|
||||
@ -109,13 +111,19 @@ struct snd_usb_midi {
|
||||
struct list_head list;
|
||||
struct timer_list error_timer;
|
||||
spinlock_t disc_lock;
|
||||
struct mutex mutex;
|
||||
u32 usb_id;
|
||||
int next_midi_device;
|
||||
|
||||
struct snd_usb_midi_endpoint {
|
||||
struct snd_usb_midi_out_endpoint *out;
|
||||
struct snd_usb_midi_in_endpoint *in;
|
||||
} endpoints[MIDI_MAX_ENDPOINTS];
|
||||
unsigned long input_triggered;
|
||||
unsigned int opened;
|
||||
unsigned char disconnected;
|
||||
|
||||
struct snd_kcontrol *roland_load_ctl;
|
||||
};
|
||||
|
||||
struct snd_usb_midi_out_endpoint {
|
||||
@ -255,7 +263,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
|
||||
}
|
||||
}
|
||||
|
||||
urb->dev = ep->umidi->chip->dev;
|
||||
urb->dev = ep->umidi->dev;
|
||||
snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
@ -296,7 +304,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ep->buffer_lock, flags);
|
||||
if (ep->umidi->chip->shutdown) {
|
||||
if (ep->umidi->disconnected) {
|
||||
spin_unlock_irqrestore(&ep->buffer_lock, flags);
|
||||
return;
|
||||
}
|
||||
@ -312,7 +320,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep)
|
||||
|
||||
dump_urb("sending", urb->transfer_buffer,
|
||||
urb->transfer_buffer_length);
|
||||
urb->dev = ep->umidi->chip->dev;
|
||||
urb->dev = ep->umidi->dev;
|
||||
if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0)
|
||||
break;
|
||||
ep->active_urbs |= 1 << urb_index;
|
||||
@ -349,7 +357,7 @@ static void snd_usbmidi_error_timer(unsigned long data)
|
||||
if (in && in->error_resubmit) {
|
||||
in->error_resubmit = 0;
|
||||
for (j = 0; j < INPUT_URBS; ++j) {
|
||||
in->urbs[j]->dev = umidi->chip->dev;
|
||||
in->urbs[j]->dev = umidi->dev;
|
||||
snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
|
||||
}
|
||||
}
|
||||
@ -369,7 +377,7 @@ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep,
|
||||
return -ENOMEM;
|
||||
dump_urb("sending", buf, len);
|
||||
if (ep->urbs[0].urb)
|
||||
err = usb_bulk_msg(ep->umidi->chip->dev, ep->urbs[0].urb->pipe,
|
||||
err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe,
|
||||
buf, len, NULL, 250);
|
||||
kfree(buf);
|
||||
return err;
|
||||
@ -724,8 +732,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
|
||||
|
||||
if (!ep->ports[0].active)
|
||||
return;
|
||||
count = snd_usb_get_speed(ep->umidi->chip->dev) == USB_SPEED_HIGH
|
||||
? 1 : 2;
|
||||
count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2;
|
||||
count = snd_rawmidi_transmit(ep->ports[0].substream,
|
||||
urb->transfer_buffer,
|
||||
count);
|
||||
@ -879,6 +886,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = {
|
||||
};
|
||||
|
||||
|
||||
static void update_roland_altsetting(struct snd_usb_midi* umidi)
|
||||
{
|
||||
struct usb_interface *intf;
|
||||
struct usb_host_interface *hostif;
|
||||
struct usb_interface_descriptor *intfd;
|
||||
int is_light_load;
|
||||
|
||||
intf = umidi->iface;
|
||||
is_light_load = intf->cur_altsetting != intf->altsetting;
|
||||
if (umidi->roland_load_ctl->private_value == is_light_load)
|
||||
return;
|
||||
hostif = &intf->altsetting[umidi->roland_load_ctl->private_value];
|
||||
intfd = get_iface_desc(hostif);
|
||||
snd_usbmidi_input_stop(&umidi->list);
|
||||
usb_set_interface(umidi->dev, intfd->bInterfaceNumber,
|
||||
intfd->bAlternateSetting);
|
||||
snd_usbmidi_input_start(&umidi->list);
|
||||
}
|
||||
|
||||
static void substream_open(struct snd_rawmidi_substream *substream, int open)
|
||||
{
|
||||
struct snd_usb_midi* umidi = substream->rmidi->private_data;
|
||||
struct snd_kcontrol *ctl;
|
||||
|
||||
mutex_lock(&umidi->mutex);
|
||||
if (open) {
|
||||
if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
|
||||
ctl = umidi->roland_load_ctl;
|
||||
ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
snd_ctl_notify(umidi->card,
|
||||
SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
|
||||
update_roland_altsetting(umidi);
|
||||
}
|
||||
} else {
|
||||
if (--umidi->opened == 0 && umidi->roland_load_ctl) {
|
||||
ctl = umidi->roland_load_ctl;
|
||||
ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
snd_ctl_notify(umidi->card,
|
||||
SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&umidi->mutex);
|
||||
}
|
||||
|
||||
static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct snd_usb_midi* umidi = substream->rmidi->private_data;
|
||||
@ -898,11 +949,13 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
|
||||
}
|
||||
substream->runtime->private_data = port;
|
||||
port->state = STATE_UNKNOWN;
|
||||
substream_open(substream, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
substream_open(substream, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -912,7 +965,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream,
|
||||
|
||||
port->active = up;
|
||||
if (up) {
|
||||
if (port->ep->umidi->chip->shutdown) {
|
||||
if (port->ep->umidi->disconnected) {
|
||||
/* gobble up remaining bytes to prevent wait in
|
||||
* snd_rawmidi_drain_output */
|
||||
while (!snd_rawmidi_transmit_empty(substream))
|
||||
@ -954,11 +1007,13 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
|
||||
|
||||
static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
substream_open(substream, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
substream_open(substream, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -988,7 +1043,7 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
|
||||
static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb,
|
||||
unsigned int buffer_length)
|
||||
{
|
||||
usb_buffer_free(umidi->chip->dev, buffer_length,
|
||||
usb_buffer_free(umidi->dev, buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
@ -1035,24 +1090,24 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
|
||||
}
|
||||
}
|
||||
if (ep_info->in_interval)
|
||||
pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep);
|
||||
pipe = usb_rcvintpipe(umidi->dev, ep_info->in_ep);
|
||||
else
|
||||
pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
|
||||
length = usb_maxpacket(umidi->chip->dev, pipe, 0);
|
||||
pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep);
|
||||
length = usb_maxpacket(umidi->dev, pipe, 0);
|
||||
for (i = 0; i < INPUT_URBS; ++i) {
|
||||
buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
|
||||
buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL,
|
||||
&ep->urbs[i]->transfer_dma);
|
||||
if (!buffer) {
|
||||
snd_usbmidi_in_endpoint_delete(ep);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (ep_info->in_interval)
|
||||
usb_fill_int_urb(ep->urbs[i], umidi->chip->dev,
|
||||
usb_fill_int_urb(ep->urbs[i], umidi->dev,
|
||||
pipe, buffer, length,
|
||||
snd_usbmidi_in_urb_complete,
|
||||
ep, ep_info->in_interval);
|
||||
else
|
||||
usb_fill_bulk_urb(ep->urbs[i], umidi->chip->dev,
|
||||
usb_fill_bulk_urb(ep->urbs[i], umidi->dev,
|
||||
pipe, buffer, length,
|
||||
snd_usbmidi_in_urb_complete, ep);
|
||||
ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
|
||||
@ -1062,15 +1117,6 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int snd_usbmidi_count_bits(unsigned int x)
|
||||
{
|
||||
unsigned int bits;
|
||||
|
||||
for (bits = 0; x; ++bits)
|
||||
x &= x - 1;
|
||||
return bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees an output endpoint.
|
||||
* May be called when ep hasn't been initialized completely.
|
||||
@ -1113,15 +1159,15 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
|
||||
ep->urbs[i].ep = ep;
|
||||
}
|
||||
if (ep_info->out_interval)
|
||||
pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep);
|
||||
pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep);
|
||||
else
|
||||
pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
|
||||
if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */
|
||||
pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep);
|
||||
if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */
|
||||
ep->max_transfer = 4;
|
||||
else
|
||||
ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
|
||||
ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1);
|
||||
for (i = 0; i < OUTPUT_URBS; ++i) {
|
||||
buffer = usb_buffer_alloc(umidi->chip->dev,
|
||||
buffer = usb_buffer_alloc(umidi->dev,
|
||||
ep->max_transfer, GFP_KERNEL,
|
||||
&ep->urbs[i].urb->transfer_dma);
|
||||
if (!buffer) {
|
||||
@ -1129,12 +1175,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (ep_info->out_interval)
|
||||
usb_fill_int_urb(ep->urbs[i].urb, umidi->chip->dev,
|
||||
usb_fill_int_urb(ep->urbs[i].urb, umidi->dev,
|
||||
pipe, buffer, ep->max_transfer,
|
||||
snd_usbmidi_out_urb_complete,
|
||||
&ep->urbs[i], ep_info->out_interval);
|
||||
else
|
||||
usb_fill_bulk_urb(ep->urbs[i].urb, umidi->chip->dev,
|
||||
usb_fill_bulk_urb(ep->urbs[i].urb, umidi->dev,
|
||||
pipe, buffer, ep->max_transfer,
|
||||
snd_usbmidi_out_urb_complete,
|
||||
&ep->urbs[i]);
|
||||
@ -1172,6 +1218,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi)
|
||||
if (ep->in)
|
||||
snd_usbmidi_in_endpoint_delete(ep->in);
|
||||
}
|
||||
mutex_destroy(&umidi->mutex);
|
||||
kfree(umidi);
|
||||
}
|
||||
|
||||
@ -1367,7 +1414,7 @@ static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) {
|
||||
if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id &&
|
||||
if (snd_usbmidi_port_info[i].id == umidi->usb_id &&
|
||||
snd_usbmidi_port_info[i].port == number)
|
||||
return &snd_usbmidi_port_info[i];
|
||||
}
|
||||
@ -1405,7 +1452,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,
|
||||
port_info = find_port_info(umidi, number);
|
||||
name_format = port_info ? port_info->name : "%s MIDI %d";
|
||||
snprintf(substream->name, sizeof(substream->name),
|
||||
name_format, umidi->chip->card->shortname, number + 1);
|
||||
name_format, umidi->card->shortname, number + 1);
|
||||
|
||||
*rsubstream = substream;
|
||||
}
|
||||
@ -1503,7 +1550,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
|
||||
endpoints[epidx].out_ep = usb_endpoint_num(ep);
|
||||
if (usb_endpoint_xfer_int(ep))
|
||||
endpoints[epidx].out_interval = ep->bInterval;
|
||||
else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW)
|
||||
else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW)
|
||||
/*
|
||||
* Low speed bulk transfers don't exist, so
|
||||
* force interrupt transfers for devices like
|
||||
@ -1523,7 +1570,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
|
||||
endpoints[epidx].in_ep = usb_endpoint_num(ep);
|
||||
if (usb_endpoint_xfer_int(ep))
|
||||
endpoints[epidx].in_interval = ep->bInterval;
|
||||
else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW)
|
||||
else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW)
|
||||
endpoints[epidx].in_interval = 1;
|
||||
endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
|
||||
snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
|
||||
@ -1533,6 +1580,52 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int roland_load_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
static const char *const names[] = { "High Load", "Light Load" };
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
info->count = 1;
|
||||
info->value.enumerated.items = 2;
|
||||
if (info->value.enumerated.item > 1)
|
||||
info->value.enumerated.item = 1;
|
||||
strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int roland_load_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
value->value.enumerated.item[0] = kcontrol->private_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int roland_load_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
struct snd_usb_midi* umidi = kcontrol->private_data;
|
||||
int changed;
|
||||
|
||||
if (value->value.enumerated.item[0] > 1)
|
||||
return -EINVAL;
|
||||
mutex_lock(&umidi->mutex);
|
||||
changed = value->value.enumerated.item[0] != kcontrol->private_value;
|
||||
if (changed)
|
||||
kcontrol->private_value = value->value.enumerated.item[0];
|
||||
mutex_unlock(&umidi->mutex);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new roland_load_ctl = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "MIDI Input Mode",
|
||||
.info = roland_load_info,
|
||||
.get = roland_load_get,
|
||||
.put = roland_load_put,
|
||||
.private_value = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* On Roland devices, use the second alternate setting to be able to use
|
||||
* the interrupt input endpoint.
|
||||
@ -1556,8 +1649,12 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi)
|
||||
|
||||
snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n",
|
||||
intfd->bAlternateSetting);
|
||||
usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
|
||||
usb_set_interface(umidi->dev, intfd->bInterfaceNumber,
|
||||
intfd->bAlternateSetting);
|
||||
|
||||
umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi);
|
||||
if (snd_ctl_add(umidi->card, umidi->roland_load_ctl) < 0)
|
||||
umidi->roland_load_ctl = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1573,7 +1670,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi,
|
||||
struct usb_endpoint_descriptor* epd;
|
||||
int i, out_eps = 0, in_eps = 0;
|
||||
|
||||
if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582)
|
||||
if (USB_ID_VENDOR(umidi->usb_id) == 0x0582)
|
||||
snd_usbmidi_switch_roland_altsetting(umidi);
|
||||
|
||||
if (endpoint[0].out_ep || endpoint[0].in_ep)
|
||||
@ -1760,12 +1857,12 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi,
|
||||
struct snd_rawmidi *rmidi;
|
||||
int err;
|
||||
|
||||
err = snd_rawmidi_new(umidi->chip->card, "USB MIDI",
|
||||
umidi->chip->next_midi_device++,
|
||||
err = snd_rawmidi_new(umidi->card, "USB MIDI",
|
||||
umidi->next_midi_device++,
|
||||
out_ports, in_ports, &rmidi);
|
||||
if (err < 0)
|
||||
return err;
|
||||
strcpy(rmidi->name, umidi->chip->card->shortname);
|
||||
strcpy(rmidi->name, umidi->card->shortname);
|
||||
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
|
||||
SNDRV_RAWMIDI_INFO_INPUT |
|
||||
SNDRV_RAWMIDI_INFO_DUPLEX;
|
||||
@ -1804,7 +1901,7 @@ static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)
|
||||
return;
|
||||
for (i = 0; i < INPUT_URBS; ++i) {
|
||||
struct urb* urb = ep->urbs[i];
|
||||
urb->dev = ep->umidi->chip->dev;
|
||||
urb->dev = ep->umidi->dev;
|
||||
snd_usbmidi_submit_urb(urb, GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
@ -1825,9 +1922,10 @@ void snd_usbmidi_input_start(struct list_head* p)
|
||||
/*
|
||||
* Creates and registers everything needed for a MIDI streaming interface.
|
||||
*/
|
||||
int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
|
||||
struct usb_interface* iface,
|
||||
const struct snd_usb_audio_quirk* quirk)
|
||||
int snd_usbmidi_create(struct snd_card *card,
|
||||
struct usb_interface* iface,
|
||||
struct list_head *midi_list,
|
||||
const struct snd_usb_audio_quirk* quirk)
|
||||
{
|
||||
struct snd_usb_midi* umidi;
|
||||
struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS];
|
||||
@ -1837,12 +1935,16 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
|
||||
umidi = kzalloc(sizeof(*umidi), GFP_KERNEL);
|
||||
if (!umidi)
|
||||
return -ENOMEM;
|
||||
umidi->chip = chip;
|
||||
umidi->dev = interface_to_usbdev(iface);
|
||||
umidi->card = card;
|
||||
umidi->iface = iface;
|
||||
umidi->quirk = quirk;
|
||||
umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
|
||||
init_timer(&umidi->error_timer);
|
||||
spin_lock_init(&umidi->disc_lock);
|
||||
mutex_init(&umidi->mutex);
|
||||
umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
|
||||
le16_to_cpu(umidi->dev->descriptor.idProduct));
|
||||
umidi->error_timer.function = snd_usbmidi_error_timer;
|
||||
umidi->error_timer.data = (unsigned long)umidi;
|
||||
|
||||
@ -1851,7 +1953,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
|
||||
switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) {
|
||||
case QUIRK_MIDI_STANDARD_INTERFACE:
|
||||
err = snd_usbmidi_get_ms_info(umidi, endpoints);
|
||||
if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */
|
||||
if (umidi->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */
|
||||
umidi->usb_protocol_ops =
|
||||
&snd_usbmidi_maudio_broken_running_status_ops;
|
||||
break;
|
||||
@ -1887,7 +1989,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
|
||||
* interface 0, so we have to make sure that the USB core looks
|
||||
* again at interface 0 by calling usb_set_interface() on it.
|
||||
*/
|
||||
usb_set_interface(umidi->chip->dev, 0, 0);
|
||||
usb_set_interface(umidi->dev, 0, 0);
|
||||
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
|
||||
break;
|
||||
case QUIRK_MIDI_EMAGIC:
|
||||
@ -1914,8 +2016,8 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
|
||||
out_ports = 0;
|
||||
in_ports = 0;
|
||||
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
|
||||
out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables);
|
||||
in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables);
|
||||
out_ports += hweight16(endpoints[i].out_cables);
|
||||
in_ports += hweight16(endpoints[i].in_cables);
|
||||
}
|
||||
err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports);
|
||||
if (err < 0) {
|
||||
@ -1933,14 +2035,14 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
|
||||
return err;
|
||||
}
|
||||
|
||||
list_add(&umidi->list, &umidi->chip->midi_list);
|
||||
list_add_tail(&umidi->list, midi_list);
|
||||
|
||||
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
|
||||
snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_usb_create_midi_interface);
|
||||
EXPORT_SYMBOL(snd_usbmidi_create);
|
||||
EXPORT_SYMBOL(snd_usbmidi_input_stop);
|
||||
EXPORT_SYMBOL(snd_usbmidi_input_start);
|
||||
EXPORT_SYMBOL(snd_usbmidi_disconnect);
|
||||
|
@ -277,6 +277,22 @@ static struct usbmix_name_map scratch_live_map[] = {
|
||||
{ 0 } /* terminator */
|
||||
};
|
||||
|
||||
/* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+"
|
||||
* most importand difference is SU[8], it should be set to "Capture Source"
|
||||
* to make alsamixer and PA working properly.
|
||||
* FIXME: or mp3plus_map should use "Capture Source" too,
|
||||
* so this maps can be merget
|
||||
*/
|
||||
static struct usbmix_name_map hercules_usb51_map[] = {
|
||||
{ 8, "Capture Source" }, /* SU, default "PCM Capture Source" */
|
||||
{ 9, "Master Playback" }, /* FU, default "Speaker Playback" */
|
||||
{ 10, "Mic Boost", 7 }, /* FU, default "Auto Gain Input" */
|
||||
{ 11, "Line Capture" }, /* FU, default "PCM Capture" */
|
||||
{ 13, "Mic Bypass Playback" }, /* FU, default "Mic Playback" */
|
||||
{ 14, "Line Bypass Playback" }, /* FU, default "Line Playback" */
|
||||
{ 0 } /* terminator */
|
||||
};
|
||||
|
||||
/*
|
||||
* Control map entries
|
||||
*/
|
||||
@ -315,6 +331,13 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
||||
.id = USB_ID(0x06f8, 0xd002),
|
||||
.ignore_ctl_error = 1,
|
||||
},
|
||||
{
|
||||
/* Hercules Gamesurround Muse Pocket LT
|
||||
* (USB 5.1 Channel Audio Adapter)
|
||||
*/
|
||||
.id = USB_ID(0x06f8, 0xc000),
|
||||
.map = hercules_usb51_map,
|
||||
},
|
||||
{
|
||||
.id = USB_ID(0x08bb, 0x2702),
|
||||
.map = linex_map,
|
||||
|
@ -1563,6 +1563,29 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* has ID 0x00ea when not in Advanced Driver mode */
|
||||
USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "Roland", */
|
||||
/* .product_name = "UA-1G", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* Guillemot devices */
|
||||
{
|
||||
|
@ -59,11 +59,11 @@ static int us122l_create_usbmidi(struct snd_card *card)
|
||||
.type = QUIRK_MIDI_US122L,
|
||||
.data = &quirk_data
|
||||
};
|
||||
struct usb_device *dev = US122L(card)->chip.dev;
|
||||
struct usb_device *dev = US122L(card)->dev;
|
||||
struct usb_interface *iface = usb_ifnum_to_if(dev, 1);
|
||||
|
||||
return snd_usb_create_midi_interface(&US122L(card)->chip,
|
||||
iface, &quirk);
|
||||
return snd_usbmidi_create(card, iface,
|
||||
&US122L(card)->midi_list, &quirk);
|
||||
}
|
||||
|
||||
static int us144_create_usbmidi(struct snd_card *card)
|
||||
@ -81,11 +81,11 @@ static int us144_create_usbmidi(struct snd_card *card)
|
||||
.type = QUIRK_MIDI_US122L,
|
||||
.data = &quirk_data
|
||||
};
|
||||
struct usb_device *dev = US122L(card)->chip.dev;
|
||||
struct usb_device *dev = US122L(card)->dev;
|
||||
struct usb_interface *iface = usb_ifnum_to_if(dev, 0);
|
||||
|
||||
return snd_usb_create_midi_interface(&US122L(card)->chip,
|
||||
iface, &quirk);
|
||||
return snd_usbmidi_create(card, iface,
|
||||
&US122L(card)->midi_list, &quirk);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -194,11 +194,11 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
|
||||
if (!us122l->first)
|
||||
us122l->first = file;
|
||||
|
||||
if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) {
|
||||
iface = usb_ifnum_to_if(us122l->chip.dev, 0);
|
||||
if (us122l->dev->descriptor.idProduct == USB_ID_US144) {
|
||||
iface = usb_ifnum_to_if(us122l->dev, 0);
|
||||
usb_autopm_get_interface(iface);
|
||||
}
|
||||
iface = usb_ifnum_to_if(us122l->chip.dev, 1);
|
||||
iface = usb_ifnum_to_if(us122l->dev, 1);
|
||||
usb_autopm_get_interface(iface);
|
||||
return 0;
|
||||
}
|
||||
@ -209,11 +209,11 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file)
|
||||
struct usb_interface *iface;
|
||||
snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
|
||||
|
||||
if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) {
|
||||
iface = usb_ifnum_to_if(us122l->chip.dev, 0);
|
||||
if (us122l->dev->descriptor.idProduct == USB_ID_US144) {
|
||||
iface = usb_ifnum_to_if(us122l->dev, 0);
|
||||
usb_autopm_put_interface(iface);
|
||||
}
|
||||
iface = usb_ifnum_to_if(us122l->chip.dev, 1);
|
||||
iface = usb_ifnum_to_if(us122l->dev, 1);
|
||||
usb_autopm_put_interface(iface);
|
||||
if (us122l->first == file)
|
||||
us122l->first = NULL;
|
||||
@ -297,7 +297,7 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw,
|
||||
static void us122l_stop(struct us122l *us122l)
|
||||
{
|
||||
struct list_head *p;
|
||||
list_for_each(p, &us122l->chip.midi_list)
|
||||
list_for_each(p, &us122l->midi_list)
|
||||
snd_usbmidi_input_stop(p);
|
||||
|
||||
usb_stream_stop(&us122l->sk);
|
||||
@ -330,7 +330,7 @@ static bool us122l_start(struct us122l *us122l,
|
||||
unsigned use_packsize = 0;
|
||||
bool success = false;
|
||||
|
||||
if (us122l->chip.dev->speed == USB_SPEED_HIGH) {
|
||||
if (us122l->dev->speed == USB_SPEED_HIGH) {
|
||||
/* The us-122l's descriptor defaults to iso max_packsize 78,
|
||||
which isn't needed for samplerates <= 48000.
|
||||
Lets save some memory:
|
||||
@ -347,11 +347,11 @@ static bool us122l_start(struct us122l *us122l,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!usb_stream_new(&us122l->sk, us122l->chip.dev, 1, 2,
|
||||
if (!usb_stream_new(&us122l->sk, us122l->dev, 1, 2,
|
||||
rate, use_packsize, period_frames, 6))
|
||||
goto out;
|
||||
|
||||
err = us122l_set_sample_rate(us122l->chip.dev, rate);
|
||||
err = us122l_set_sample_rate(us122l->dev, rate);
|
||||
if (err < 0) {
|
||||
us122l_stop(us122l);
|
||||
snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
|
||||
@ -363,7 +363,7 @@ static bool us122l_start(struct us122l *us122l,
|
||||
snd_printk(KERN_ERR "us122l_start error %i \n", err);
|
||||
goto out;
|
||||
}
|
||||
list_for_each(p, &us122l->chip.midi_list)
|
||||
list_for_each(p, &us122l->midi_list)
|
||||
snd_usbmidi_input_start(p);
|
||||
success = true;
|
||||
out:
|
||||
@ -390,7 +390,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
|
||||
err = -ENXIO;
|
||||
goto free;
|
||||
}
|
||||
high_speed = us122l->chip.dev->speed == USB_SPEED_HIGH;
|
||||
high_speed = us122l->dev->speed == USB_SPEED_HIGH;
|
||||
if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000 &&
|
||||
(!high_speed ||
|
||||
(cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) ||
|
||||
@ -450,7 +450,7 @@ static int usb_stream_hwdep_new(struct snd_card *card)
|
||||
{
|
||||
int err;
|
||||
struct snd_hwdep *hw;
|
||||
struct usb_device *dev = US122L(card)->chip.dev;
|
||||
struct usb_device *dev = US122L(card)->dev;
|
||||
|
||||
err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw);
|
||||
if (err < 0)
|
||||
@ -476,26 +476,26 @@ static bool us122l_create_card(struct snd_card *card)
|
||||
int err;
|
||||
struct us122l *us122l = US122L(card);
|
||||
|
||||
if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) {
|
||||
err = usb_set_interface(us122l->chip.dev, 0, 1);
|
||||
if (us122l->dev->descriptor.idProduct == USB_ID_US144) {
|
||||
err = usb_set_interface(us122l->dev, 0, 1);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "usb_set_interface error \n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
err = usb_set_interface(us122l->chip.dev, 1, 1);
|
||||
err = usb_set_interface(us122l->dev, 1, 1);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "usb_set_interface error \n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pt_info_set(us122l->chip.dev, 0x11);
|
||||
pt_info_set(us122l->chip.dev, 0x10);
|
||||
pt_info_set(us122l->dev, 0x11);
|
||||
pt_info_set(us122l->dev, 0x10);
|
||||
|
||||
if (!us122l_start(us122l, 44100, 256))
|
||||
return false;
|
||||
|
||||
if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144)
|
||||
if (us122l->dev->descriptor.idProduct == USB_ID_US144)
|
||||
err = us144_create_usbmidi(card);
|
||||
else
|
||||
err = us122l_create_usbmidi(card);
|
||||
@ -508,7 +508,7 @@ static bool us122l_create_card(struct snd_card *card)
|
||||
if (err < 0) {
|
||||
/* release the midi resources */
|
||||
struct list_head *p;
|
||||
list_for_each(p, &us122l->chip.midi_list)
|
||||
list_for_each(p, &us122l->midi_list)
|
||||
snd_usbmidi_disconnect(p);
|
||||
|
||||
us122l_stop(us122l);
|
||||
@ -520,7 +520,7 @@ static bool us122l_create_card(struct snd_card *card)
|
||||
static void snd_us122l_free(struct snd_card *card)
|
||||
{
|
||||
struct us122l *us122l = US122L(card);
|
||||
int index = us122l->chip.index;
|
||||
int index = us122l->card_index;
|
||||
if (index >= 0 && index < SNDRV_CARDS)
|
||||
snd_us122l_card_used[index] = 0;
|
||||
}
|
||||
@ -540,13 +540,12 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
|
||||
sizeof(struct us122l), &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_us122l_card_used[US122L(card)->chip.index = dev] = 1;
|
||||
snd_us122l_card_used[US122L(card)->card_index = dev] = 1;
|
||||
card->private_free = snd_us122l_free;
|
||||
US122L(card)->chip.dev = device;
|
||||
US122L(card)->chip.card = card;
|
||||
US122L(card)->dev = device;
|
||||
mutex_init(&US122L(card)->mutex);
|
||||
init_waitqueue_head(&US122L(card)->sk.sleep);
|
||||
INIT_LIST_HEAD(&US122L(card)->chip.midi_list);
|
||||
INIT_LIST_HEAD(&US122L(card)->midi_list);
|
||||
strcpy(card->driver, "USB "NAME_ALLCAPS"");
|
||||
sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
|
||||
sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
|
||||
@ -554,8 +553,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
|
||||
le16_to_cpu(device->descriptor.idVendor),
|
||||
le16_to_cpu(device->descriptor.idProduct),
|
||||
0,
|
||||
US122L(card)->chip.dev->bus->busnum,
|
||||
US122L(card)->chip.dev->devnum
|
||||
US122L(card)->dev->bus->busnum,
|
||||
US122L(card)->dev->devnum
|
||||
);
|
||||
*cardp = card;
|
||||
return 0;
|
||||
@ -635,16 +634,15 @@ static void snd_us122l_disconnect(struct usb_interface *intf)
|
||||
mutex_lock(&us122l->mutex);
|
||||
us122l_stop(us122l);
|
||||
mutex_unlock(&us122l->mutex);
|
||||
us122l->chip.shutdown = 1;
|
||||
|
||||
/* release the midi resources */
|
||||
list_for_each(p, &us122l->chip.midi_list) {
|
||||
list_for_each(p, &us122l->midi_list) {
|
||||
snd_usbmidi_disconnect(p);
|
||||
}
|
||||
|
||||
usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 0));
|
||||
usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 1));
|
||||
usb_put_dev(us122l->chip.dev);
|
||||
usb_put_intf(usb_ifnum_to_if(us122l->dev, 0));
|
||||
usb_put_intf(usb_ifnum_to_if(us122l->dev, 1));
|
||||
usb_put_dev(us122l->dev);
|
||||
|
||||
while (atomic_read(&us122l->mmap_count))
|
||||
msleep(500);
|
||||
@ -667,7 +665,7 @@ static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
if (!us122l)
|
||||
return 0;
|
||||
|
||||
list_for_each(p, &us122l->chip.midi_list)
|
||||
list_for_each(p, &us122l->midi_list)
|
||||
snd_usbmidi_input_stop(p);
|
||||
|
||||
mutex_lock(&us122l->mutex);
|
||||
@ -694,23 +692,23 @@ static int snd_us122l_resume(struct usb_interface *intf)
|
||||
|
||||
mutex_lock(&us122l->mutex);
|
||||
/* needed, doesn't restart without: */
|
||||
if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) {
|
||||
err = usb_set_interface(us122l->chip.dev, 0, 1);
|
||||
if (us122l->dev->descriptor.idProduct == USB_ID_US144) {
|
||||
err = usb_set_interface(us122l->dev, 0, 1);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "usb_set_interface error \n");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
err = usb_set_interface(us122l->chip.dev, 1, 1);
|
||||
err = usb_set_interface(us122l->dev, 1, 1);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR "usb_set_interface error \n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
pt_info_set(us122l->chip.dev, 0x11);
|
||||
pt_info_set(us122l->chip.dev, 0x10);
|
||||
pt_info_set(us122l->dev, 0x11);
|
||||
pt_info_set(us122l->dev, 0x10);
|
||||
|
||||
err = us122l_set_sample_rate(us122l->chip.dev,
|
||||
err = us122l_set_sample_rate(us122l->dev,
|
||||
us122l->sk.s->cfg.sample_rate);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "us122l_set_sample_rate error \n");
|
||||
@ -720,7 +718,7 @@ static int snd_us122l_resume(struct usb_interface *intf)
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
list_for_each(p, &us122l->chip.midi_list)
|
||||
list_for_each(p, &us122l->midi_list)
|
||||
snd_usbmidi_input_start(p);
|
||||
unlock:
|
||||
mutex_unlock(&us122l->mutex);
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
|
||||
struct us122l {
|
||||
struct snd_usb_audio chip;
|
||||
struct usb_device *dev;
|
||||
int card_index;
|
||||
int stride;
|
||||
struct usb_stream_kernel sk;
|
||||
|
||||
@ -12,6 +13,7 @@ struct us122l {
|
||||
unsigned second_periods_polled;
|
||||
struct file *master;
|
||||
struct file *slave;
|
||||
struct list_head midi_list;
|
||||
|
||||
atomic_t mmap_count;
|
||||
};
|
||||
|
@ -114,7 +114,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw,
|
||||
struct usX2Ydev *us428 = hw->private_data;
|
||||
int id = -1;
|
||||
|
||||
switch (le16_to_cpu(us428->chip.dev->descriptor.idProduct)) {
|
||||
switch (le16_to_cpu(us428->dev->descriptor.idProduct)) {
|
||||
case USB_ID_US122:
|
||||
id = USX2Y_TYPE_122;
|
||||
break;
|
||||
@ -164,14 +164,14 @@ static int usX2Y_create_usbmidi(struct snd_card *card)
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = &quirk_data_2
|
||||
};
|
||||
struct usb_device *dev = usX2Y(card)->chip.dev;
|
||||
struct usb_device *dev = usX2Y(card)->dev;
|
||||
struct usb_interface *iface = usb_ifnum_to_if(dev, 0);
|
||||
struct snd_usb_audio_quirk *quirk =
|
||||
le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ?
|
||||
&quirk_2 : &quirk_1;
|
||||
|
||||
snd_printdd("usX2Y_create_usbmidi \n");
|
||||
return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk);
|
||||
return snd_usbmidi_create(card, iface, &usX2Y(card)->midi_list, quirk);
|
||||
}
|
||||
|
||||
static int usX2Y_create_alsa_devices(struct snd_card *card)
|
||||
@ -202,7 +202,7 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw,
|
||||
snd_printdd( "dsp_load %s\n", dsp->name);
|
||||
|
||||
if (access_ok(VERIFY_READ, dsp->image, dsp->length)) {
|
||||
struct usb_device* dev = priv->chip.dev;
|
||||
struct usb_device* dev = priv->dev;
|
||||
char *buf;
|
||||
|
||||
buf = memdup_user(dsp->image, dsp->length);
|
||||
|
@ -239,8 +239,8 @@ static void i_usX2Y_In04Int(struct urb *urb)
|
||||
for (j = 0; j < URBS_AsyncSeq && !err; ++j)
|
||||
if (0 == usX2Y->AS04.urb[j]->status) {
|
||||
struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost.
|
||||
usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev,
|
||||
usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol,
|
||||
usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->dev,
|
||||
usb_sndbulkpipe(usX2Y->dev, 0x04), &p4out->val.vol,
|
||||
p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5,
|
||||
i_usX2Y_Out04Int, usX2Y);
|
||||
err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC);
|
||||
@ -253,7 +253,7 @@ static void i_usX2Y_In04Int(struct urb *urb)
|
||||
if (err)
|
||||
snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err);
|
||||
|
||||
urb->dev = usX2Y->chip.dev;
|
||||
urb->dev = usX2Y->dev;
|
||||
usb_submit_urb(urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
@ -273,8 +273,8 @@ int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y)
|
||||
err = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->chip.dev,
|
||||
usb_sndbulkpipe(usX2Y->chip.dev, 0x04),
|
||||
usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->dev,
|
||||
usb_sndbulkpipe(usX2Y->dev, 0x04),
|
||||
usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0,
|
||||
i_usX2Y_Out04Int, usX2Y
|
||||
);
|
||||
@ -293,7 +293,7 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y)
|
||||
}
|
||||
|
||||
init_waitqueue_head(&usX2Y->In04WaitQueue);
|
||||
usb_fill_int_urb(usX2Y->In04urb, usX2Y->chip.dev, usb_rcvintpipe(usX2Y->chip.dev, 0x4),
|
||||
usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4),
|
||||
usX2Y->In04Buf, 21,
|
||||
i_usX2Y_In04Int, usX2Y,
|
||||
10);
|
||||
@ -348,13 +348,12 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
|
||||
sizeof(struct usX2Ydev), &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1;
|
||||
snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1;
|
||||
card->private_free = snd_usX2Y_card_private_free;
|
||||
usX2Y(card)->chip.dev = device;
|
||||
usX2Y(card)->chip.card = card;
|
||||
usX2Y(card)->dev = device;
|
||||
init_waitqueue_head(&usX2Y(card)->prepare_wait_queue);
|
||||
mutex_init(&usX2Y(card)->prepare_mutex);
|
||||
INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list);
|
||||
INIT_LIST_HEAD(&usX2Y(card)->midi_list);
|
||||
strcpy(card->driver, "USB "NAME_ALLCAPS"");
|
||||
sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
|
||||
sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
|
||||
@ -362,7 +361,7 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
|
||||
le16_to_cpu(device->descriptor.idVendor),
|
||||
le16_to_cpu(device->descriptor.idProduct),
|
||||
0,//us428(card)->usbmidi.ifnum,
|
||||
usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum
|
||||
usX2Y(card)->dev->bus->busnum, usX2Y(card)->dev->devnum
|
||||
);
|
||||
*cardp = card;
|
||||
return 0;
|
||||
@ -432,8 +431,8 @@ static void snd_usX2Y_card_private_free(struct snd_card *card)
|
||||
usb_free_urb(usX2Y(card)->In04urb);
|
||||
if (usX2Y(card)->us428ctls_sharedmem)
|
||||
snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem));
|
||||
if (usX2Y(card)->chip.index >= 0 && usX2Y(card)->chip.index < SNDRV_CARDS)
|
||||
snd_usX2Y_card_used[usX2Y(card)->chip.index] = 0;
|
||||
if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS)
|
||||
snd_usX2Y_card_used[usX2Y(card)->card_index] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -445,13 +444,12 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr)
|
||||
struct snd_card *card = ptr;
|
||||
struct usX2Ydev *usX2Y = usX2Y(card);
|
||||
struct list_head *p;
|
||||
usX2Y->chip.shutdown = 1;
|
||||
usX2Y->chip_status = USX2Y_STAT_CHIP_HUP;
|
||||
usX2Y_unlinkSeq(&usX2Y->AS04);
|
||||
usb_kill_urb(usX2Y->In04urb);
|
||||
snd_card_disconnect(card);
|
||||
/* release the midi resources */
|
||||
list_for_each(p, &usX2Y->chip.midi_list) {
|
||||
list_for_each(p, &usX2Y->midi_list) {
|
||||
snd_usbmidi_disconnect(p);
|
||||
}
|
||||
if (usX2Y->us428ctls_sharedmem)
|
||||
|
@ -22,7 +22,8 @@ struct snd_usX2Y_urbSeq {
|
||||
#include "usx2yhwdeppcm.h"
|
||||
|
||||
struct usX2Ydev {
|
||||
struct snd_usb_audio chip;
|
||||
struct usb_device *dev;
|
||||
int card_index;
|
||||
int stride;
|
||||
struct urb *In04urb;
|
||||
void *In04Buf;
|
||||
@ -42,6 +43,9 @@ struct usX2Ydev {
|
||||
struct snd_usX2Y_substream *subs[4];
|
||||
struct snd_usX2Y_substream * volatile prepare_subs;
|
||||
wait_queue_head_t prepare_wait_queue;
|
||||
struct list_head midi_list;
|
||||
struct list_head pcm_list;
|
||||
int pcm_devs;
|
||||
};
|
||||
|
||||
|
||||
|
@ -199,7 +199,7 @@ static int usX2Y_urb_submit(struct snd_usX2Y_substream *subs, struct urb *urb, i
|
||||
return -ENODEV;
|
||||
urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks
|
||||
urb->hcpriv = NULL;
|
||||
urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */
|
||||
urb->dev = subs->usX2Y->dev; /* we need to set this at each time */
|
||||
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
|
||||
snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err);
|
||||
return err;
|
||||
@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y,
|
||||
"Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
|
||||
"Most propably some urb of usb-frame %i is still missing.\n"
|
||||
"Cause could be too long delays in usb-hcd interrupt handling.\n",
|
||||
usb_get_current_frame_number(usX2Y->chip.dev),
|
||||
usb_get_current_frame_number(usX2Y->dev),
|
||||
subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
|
||||
usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame);
|
||||
usX2Y_clients_stop(usX2Y);
|
||||
@ -313,7 +313,7 @@ static void i_usX2Y_urb_complete(struct urb *urb)
|
||||
|
||||
if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
|
||||
snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
|
||||
usb_get_current_frame_number(usX2Y->chip.dev),
|
||||
usb_get_current_frame_number(usX2Y->dev),
|
||||
subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
|
||||
urb->status, urb->start_frame);
|
||||
return;
|
||||
@ -424,7 +424,7 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs)
|
||||
int i;
|
||||
unsigned int pipe;
|
||||
int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
struct usb_device *dev = subs->usX2Y->chip.dev;
|
||||
struct usb_device *dev = subs->usX2Y->dev;
|
||||
|
||||
pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
|
||||
usb_rcvisocpipe(dev, subs->endpoint);
|
||||
@ -500,7 +500,7 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs)
|
||||
unsigned long pack;
|
||||
if (0 == i)
|
||||
atomic_set(&subs->state, state_STARTING3);
|
||||
urb->dev = usX2Y->chip.dev;
|
||||
urb->dev = usX2Y->dev;
|
||||
urb->transfer_flags = URB_ISO_ASAP;
|
||||
for (pack = 0; pack < nr_of_packs(); pack++) {
|
||||
urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
|
||||
@ -692,7 +692,7 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate)
|
||||
}
|
||||
((char*)(usbdata + i))[0] = ra[i].c1;
|
||||
((char*)(usbdata + i))[1] = ra[i].c2;
|
||||
usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4),
|
||||
usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4),
|
||||
usbdata + i, 2, i_usX2Y_04Int, usX2Y);
|
||||
#ifdef OLD_USB
|
||||
us->urb[i]->transfer_flags = USB_QUEUE_BULK;
|
||||
@ -740,17 +740,17 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format)
|
||||
alternate = 1;
|
||||
usX2Y->stride = 4;
|
||||
}
|
||||
list_for_each(p, &usX2Y->chip.midi_list) {
|
||||
list_for_each(p, &usX2Y->midi_list) {
|
||||
snd_usbmidi_input_stop(p);
|
||||
}
|
||||
usb_kill_urb(usX2Y->In04urb);
|
||||
if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) {
|
||||
if ((err = usb_set_interface(usX2Y->dev, 0, alternate))) {
|
||||
snd_printk(KERN_ERR "usb_set_interface error \n");
|
||||
return err;
|
||||
}
|
||||
usX2Y->In04urb->dev = usX2Y->chip.dev;
|
||||
usX2Y->In04urb->dev = usX2Y->dev;
|
||||
err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL);
|
||||
list_for_each(p, &usX2Y->chip.midi_list) {
|
||||
list_for_each(p, &usX2Y->midi_list) {
|
||||
snd_usbmidi_input_start(p);
|
||||
}
|
||||
usX2Y->format = format;
|
||||
@ -955,7 +955,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
|
||||
struct snd_pcm *pcm;
|
||||
int err, i;
|
||||
struct snd_usX2Y_substream **usX2Y_substream =
|
||||
usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs;
|
||||
usX2Y(card)->subs + 2 * usX2Y(card)->pcm_devs;
|
||||
|
||||
for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
|
||||
i <= SNDRV_PCM_STREAM_CAPTURE; ++i) {
|
||||
@ -971,7 +971,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
|
||||
usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint;
|
||||
usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint;
|
||||
|
||||
err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs,
|
||||
err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->pcm_devs,
|
||||
playback_endpoint ? 1 : 0, 1,
|
||||
&pcm);
|
||||
if (err < 0) {
|
||||
@ -987,7 +987,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
|
||||
pcm->private_free = snd_usX2Y_pcm_private_free;
|
||||
pcm->info_flags = 0;
|
||||
|
||||
sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs);
|
||||
sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs);
|
||||
|
||||
if ((playback_endpoint &&
|
||||
0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
|
||||
@ -1001,7 +1001,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
|
||||
snd_usX2Y_pcm_private_free(pcm);
|
||||
return err;
|
||||
}
|
||||
usX2Y(card)->chip.pcm_devs++;
|
||||
usX2Y(card)->pcm_devs++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1013,14 +1013,14 @@ int usX2Y_audio_create(struct snd_card *card)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list);
|
||||
INIT_LIST_HEAD(&usX2Y(card)->pcm_list);
|
||||
|
||||
if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8)))
|
||||
return err;
|
||||
if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) == USB_ID_US428)
|
||||
if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) == USB_ID_US428)
|
||||
if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA)))
|
||||
return err;
|
||||
if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) != USB_ID_US122)
|
||||
if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) != USB_ID_US122)
|
||||
err = usX2Y_rate_set(usX2Y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122.
|
||||
return err;
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
|
||||
|
||||
if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
|
||||
snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
|
||||
usb_get_current_frame_number(usX2Y->chip.dev),
|
||||
usb_get_current_frame_number(usX2Y->dev),
|
||||
subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
|
||||
urb->status, urb->start_frame);
|
||||
return;
|
||||
@ -318,7 +318,7 @@ static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
|
||||
int i;
|
||||
unsigned int pipe;
|
||||
int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
struct usb_device *dev = subs->usX2Y->chip.dev;
|
||||
struct usb_device *dev = subs->usX2Y->dev;
|
||||
|
||||
pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
|
||||
usb_rcvisocpipe(dev, subs->endpoint);
|
||||
@ -441,7 +441,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
|
||||
unsigned long pack;
|
||||
if (0 == u)
|
||||
atomic_set(&subs->state, state_STARTING3);
|
||||
urb->dev = usX2Y->chip.dev;
|
||||
urb->dev = usX2Y->dev;
|
||||
urb->transfer_flags = URB_ISO_ASAP;
|
||||
for (pack = 0; pack < nr_of_packs(); pack++) {
|
||||
urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
|
||||
@ -741,7 +741,7 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card)
|
||||
int err;
|
||||
struct snd_hwdep *hw;
|
||||
struct snd_pcm *pcm;
|
||||
struct usb_device *dev = usX2Y(card)->chip.dev;
|
||||
struct usb_device *dev = usX2Y(card)->dev;
|
||||
if (1 != nr_of_packs())
|
||||
return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user