Merge branch 'next/isa' into topic/misc

This commit is contained in:
Takashi Iwai 2009-11-27 13:27:03 +01:00
commit abe6becb7c
5 changed files with 456 additions and 109 deletions

View file

@ -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

View file

@ -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

View 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);

View file

@ -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_ */

View file

@ -40,7 +40,7 @@
#define SNDRV_LEGACY_FIND_FREE_IRQ
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
#include "miro.h"
#include <sound/aci.h>
MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>");
MODULE_LICENSE("GPL");
@ -96,7 +96,6 @@ MODULE_PARM_DESC(ide, "enable ide port");
#define OPTi9XX_MC_REG(n) n
struct snd_miro {
unsigned short hardware;
unsigned char password;
@ -120,17 +119,11 @@ struct snd_miro {
long mpu_port;
int mpu_irq;
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;
struct snd_miro_aci *aci;
};
static struct snd_miro_aci aci_device;
static char * snd_opti9xx_names[] = {
"unkown",
"82C928", "82C929",
@ -142,13 +135,14 @@ static char * snd_opti9xx_names[] = {
* ACI control
*/
static int aci_busy_wait(struct snd_miro * miro)
static int aci_busy_wait(struct snd_miro_aci *aci)
{
long timeout;
unsigned char byte;
for (timeout = 1; timeout <= ACI_MINTIME+30; timeout++) {
if (((byte=inb(miro->aci_port + ACI_REG_BUSY)) & 1) == 0) {
for (timeout = 1; timeout <= ACI_MINTIME + 30; timeout++) {
byte = inb(aci->aci_port + ACI_REG_BUSY);
if ((byte & 1) == 0) {
if (timeout >= ACI_MINTIME)
snd_printd("aci ready in round %ld.\n",
timeout-ACI_MINTIME);
@ -174,10 +168,10 @@ static int aci_busy_wait(struct snd_miro * miro)
return -EBUSY;
}
static inline int aci_write(struct snd_miro * miro, unsigned char byte)
static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte)
{
if (aci_busy_wait(miro) >= 0) {
outb(byte, miro->aci_port + ACI_REG_COMMAND);
if (aci_busy_wait(aci) >= 0) {
outb(byte, aci->aci_port + ACI_REG_COMMAND);
return 0;
} else {
snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte);
@ -185,12 +179,12 @@ static inline int aci_write(struct snd_miro * miro, unsigned char byte)
}
}
static inline int aci_read(struct snd_miro * miro)
static inline int aci_read(struct snd_miro_aci *aci)
{
unsigned char byte;
if (aci_busy_wait(miro) >= 0) {
byte=inb(miro->aci_port + ACI_REG_STATUS);
if (aci_busy_wait(aci) >= 0) {
byte = inb(aci->aci_port + ACI_REG_STATUS);
return byte;
} else {
snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n");
@ -198,40 +192,50 @@ static inline int aci_read(struct snd_miro * miro)
}
}
static int aci_cmd(struct snd_miro * miro, int write1, int write2, int write3)
int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3)
{
int write[] = {write1, write2, write3};
int value, i;
if (mutex_lock_interruptible(&miro->aci_mutex))
if (mutex_lock_interruptible(&aci->aci_mutex))
return -EINTR;
for (i=0; i<3; i++) {
if (write[i]< 0 || write[i] > 255)
break;
else {
value = aci_write(miro, write[i]);
value = aci_write(aci, write[i]);
if (value < 0)
goto out;
}
}
value = aci_read(miro);
value = aci_read(aci);
out: mutex_unlock(&miro->aci_mutex);
out: mutex_unlock(&aci->aci_mutex);
return value;
}
EXPORT_SYMBOL(snd_aci_cmd);
static int aci_getvalue(struct snd_miro * miro, unsigned char index)
static int aci_getvalue(struct snd_miro_aci *aci, unsigned char index)
{
return aci_cmd(miro, ACI_STATUS, index, -1);
return snd_aci_cmd(aci, ACI_STATUS, index, -1);
}
static int aci_setvalue(struct snd_miro * miro, unsigned char index, int value)
static int aci_setvalue(struct snd_miro_aci *aci, unsigned char index,
int value)
{
return aci_cmd(miro, index, value, -1);
return snd_aci_cmd(aci, index, value, -1);
}
struct snd_miro_aci *snd_aci_get_aci(void)
{
if (aci_device.aci_port == 0)
return NULL;
return &aci_device;
}
EXPORT_SYMBOL(snd_aci_get_aci);
/*
* MIXER part
*/
@ -244,8 +248,10 @@ static int snd_miro_get_capture(struct snd_kcontrol *kcontrol,
struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
int value;
if ((value = aci_getvalue(miro, ACI_S_GENERAL)) < 0) {
snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", value);
value = aci_getvalue(miro->aci, ACI_S_GENERAL);
if (value < 0) {
snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n",
value);
return value;
}
@ -262,13 +268,15 @@ static int snd_miro_put_capture(struct snd_kcontrol *kcontrol,
value = !(ucontrol->value.integer.value[0]);
if ((error = aci_setvalue(miro, ACI_SET_SOLOMODE, value)) < 0) {
snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", error);
error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value);
if (error < 0) {
snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n",
error);
return error;
}
change = (value != miro->aci_solomode);
miro->aci_solomode = value;
change = (value != miro->aci->aci_solomode);
miro->aci->aci_solomode = value;
return change;
}
@ -290,7 +298,7 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol,
struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
int value;
if (miro->aci_version <= 176) {
if (miro->aci->aci_version <= 176) {
/*
OSS says it's not readable with versions < 176.
@ -298,12 +306,14 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol,
which is a PCM12 with aci_version = 176.
*/
ucontrol->value.integer.value[0] = miro->aci_preamp;
ucontrol->value.integer.value[0] = miro->aci->aci_preamp;
return 0;
}
if ((value = aci_getvalue(miro, ACI_GET_PREAMP)) < 0) {
snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", value);
value = aci_getvalue(miro->aci, ACI_GET_PREAMP);
if (value < 0) {
snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n",
value);
return value;
}
@ -320,13 +330,15 @@ static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol,
value = ucontrol->value.integer.value[0];
if ((error = aci_setvalue(miro, ACI_SET_PREAMP, value)) < 0) {
snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", error);
error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value);
if (error < 0) {
snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n",
error);
return error;
}
change = (value != miro->aci_preamp);
miro->aci_preamp = value;
change = (value != miro->aci->aci_preamp);
miro->aci->aci_preamp = value;
return change;
}
@ -337,7 +349,7 @@ static int snd_miro_get_amp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = miro->aci_amp;
ucontrol->value.integer.value[0] = miro->aci->aci_amp;
return 0;
}
@ -350,13 +362,14 @@ static int snd_miro_put_amp(struct snd_kcontrol *kcontrol,
value = ucontrol->value.integer.value[0];
if ((error = aci_setvalue(miro, ACI_SET_POWERAMP, value)) < 0) {
error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value);
if (error < 0) {
snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error);
return error;
}
change = (value != miro->aci_amp);
miro->aci_amp = value;
change = (value != miro->aci->aci_amp);
miro->aci->aci_amp = value;
return change;
}
@ -405,12 +418,14 @@ static int snd_miro_get_double(struct snd_kcontrol *kcontrol,
int right_reg = kcontrol->private_value & 0xff;
int left_reg = right_reg + 1;
if ((right_val = aci_getvalue(miro, right_reg)) < 0) {
right_val = aci_getvalue(miro->aci, right_reg);
if (right_val < 0) {
snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val);
return right_val;
}
if ((left_val = aci_getvalue(miro, left_reg)) < 0) {
left_val = aci_getvalue(miro->aci, left_reg);
if (left_val < 0) {
snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val);
return left_val;
}
@ -446,6 +461,7 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
struct snd_miro_aci *aci = miro->aci;
int left, right, left_old, right_old;
int setreg_left, setreg_right, getreg_left, getreg_right;
int change, error;
@ -461,12 +477,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
getreg_right = kcontrol->private_value & 0xff;
getreg_left = getreg_right + 1;
if ((left_old = aci_getvalue(miro, getreg_left)) < 0) {
left_old = aci_getvalue(aci, getreg_left);
if (left_old < 0) {
snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old);
return left_old;
}
if ((right_old = aci_getvalue(miro, getreg_right)) < 0) {
right_old = aci_getvalue(aci, getreg_right);
if (right_old < 0) {
snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old);
return right_old;
}
@ -485,13 +503,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
right_old = 0x80 - right_old;
if (left >= 0) {
if ((error = aci_setvalue(miro, setreg_left, left)) < 0) {
error = aci_setvalue(aci, setreg_left, left);
if (error < 0) {
snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
left, error);
return error;
}
} else {
if ((error = aci_setvalue(miro, setreg_left, 0x80 - left)) < 0) {
error = aci_setvalue(aci, setreg_left, 0x80 - left);
if (error < 0) {
snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
0x80 - left, error);
return error;
@ -499,13 +519,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
}
if (right >= 0) {
if ((error = aci_setvalue(miro, setreg_right, right)) < 0) {
error = aci_setvalue(aci, setreg_right, right);
if (error < 0) {
snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
right, error);
return error;
}
} else {
if ((error = aci_setvalue(miro, setreg_right, 0x80 - right)) < 0) {
error = aci_setvalue(aci, setreg_right, 0x80 - right);
if (error < 0) {
snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
0x80 - right, error);
return error;
@ -523,12 +545,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
left_old = 0x20 - left_old;
right_old = 0x20 - right_old;
if ((error = aci_setvalue(miro, setreg_left, 0x20 - left)) < 0) {
error = aci_setvalue(aci, setreg_left, 0x20 - left);
if (error < 0) {
snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
0x20 - left, error);
return error;
}
if ((error = aci_setvalue(miro, setreg_right, 0x20 - right)) < 0) {
error = aci_setvalue(aci, setreg_right, 0x20 - right);
if (error < 0) {
snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
0x20 - right, error);
return error;
@ -626,11 +650,13 @@ static unsigned char aci_init_values[][2] __devinitdata = {
static int __devinit snd_set_aci_init_values(struct snd_miro *miro)
{
int idx, error;
struct snd_miro_aci *aci = miro->aci;
/* enable WSS on PCM1 */
if ((miro->aci_product == 'A') && wss) {
if ((error = aci_setvalue(miro, ACI_SET_WSS, wss)) < 0) {
if ((aci->aci_product == 'A') && wss) {
error = aci_setvalue(aci, ACI_SET_WSS, wss);
if (error < 0) {
snd_printk(KERN_ERR "enabling WSS mode failed\n");
return error;
}
@ -639,7 +665,8 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro)
/* enable IDE port */
if (ide) {
if ((error = aci_setvalue(miro, ACI_SET_IDE, ide)) < 0) {
error = aci_setvalue(aci, ACI_SET_IDE, ide);
if (error < 0) {
snd_printk(KERN_ERR "enabling IDE port failed\n");
return error;
}
@ -647,17 +674,18 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro)
/* set common aci values */
for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++)
if ((error = aci_setvalue(miro, aci_init_values[idx][0],
aci_init_values[idx][1])) < 0) {
for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) {
error = aci_setvalue(aci, aci_init_values[idx][0],
aci_init_values[idx][1]);
if (error < 0) {
snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
aci_init_values[idx][0], error);
return error;
}
miro->aci_amp = 0;
miro->aci_preamp = 0;
miro->aci_solomode = 1;
}
aci->aci_amp = 0;
aci->aci_preamp = 0;
aci->aci_solomode = 1;
return 0;
}
@ -688,7 +716,8 @@ static int __devinit snd_miro_mixer(struct snd_card *card,
return err;
}
if ((miro->aci_product == 'A') || (miro->aci_product == 'B')) {
if ((miro->aci->aci_product == 'A') ||
(miro->aci->aci_product == 'B')) {
/* PCM1/PCM12 with power-amp and Line 2 */
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0)
return err;
@ -696,16 +725,17 @@ static int __devinit snd_miro_mixer(struct snd_card *card,
return err;
}
if ((miro->aci_product == 'B') || (miro->aci_product == 'C')) {
if ((miro->aci->aci_product == 'B') ||
(miro->aci->aci_product == 'C')) {
/* PCM12/PCM20 with mic-preamp */
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0)
return err;
if (miro->aci_version >= 176)
if (miro->aci->aci_version >= 176)
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0)
return err;
}
if (miro->aci_product == 'C') {
if (miro->aci->aci_product == 'C') {
/* PCM20 with radio and 7 band equalizer */
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0)
return err;
@ -843,14 +873,15 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
struct snd_info_buffer *buffer)
{
struct snd_miro *miro = (struct snd_miro *) entry->private_data;
struct snd_miro_aci *aci = miro->aci;
char* model = "unknown";
/* miroSOUND PCM1 pro, early PCM12 */
if ((miro->hardware == OPTi9XX_HW_82C929) &&
(miro->aci_vendor == 'm') &&
(miro->aci_product == 'A')) {
switch(miro->aci_version) {
(aci->aci_vendor == 'm') &&
(aci->aci_product == 'A')) {
switch (aci->aci_version) {
case 3:
model = "miroSOUND PCM1 pro";
break;
@ -863,9 +894,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
/* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */
if ((miro->hardware == OPTi9XX_HW_82C924) &&
(miro->aci_vendor == 'm') &&
(miro->aci_product == 'B')) {
switch(miro->aci_version) {
(aci->aci_vendor == 'm') &&
(aci->aci_product == 'B')) {
switch (aci->aci_version) {
case 4:
model = "miroSOUND PCM12";
break;
@ -881,9 +912,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
/* miroSOUND PCM20 radio */
if ((miro->hardware == OPTi9XX_HW_82C924) &&
(miro->aci_vendor == 'm') &&
(miro->aci_product == 'C')) {
switch(miro->aci_version) {
(aci->aci_vendor == 'm') &&
(aci->aci_product == 'C')) {
switch (aci->aci_version) {
case 7:
model = "miroSOUND PCM20 radio (Rev. E)";
break;
@ -907,17 +938,17 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
snd_iprintf(buffer, "ACI information:\n");
snd_iprintf(buffer, " vendor : ");
switch(miro->aci_vendor) {
switch (aci->aci_vendor) {
case 'm':
snd_iprintf(buffer, "Miro\n");
break;
default:
snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_vendor);
snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_vendor);
break;
}
snd_iprintf(buffer, " product : ");
switch(miro->aci_product) {
switch (aci->aci_product) {
case 'A':
snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n");
break;
@ -928,19 +959,19 @@ static void snd_miro_proc_read(struct snd_info_entry * entry,
snd_iprintf(buffer, "miroSOUND PCM20 radio\n");
break;
default:
snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_product);
snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_product);
break;
}
snd_iprintf(buffer, " firmware: %d (0x%x)\n",
miro->aci_version, miro->aci_version);
aci->aci_version, aci->aci_version);
snd_iprintf(buffer, " port : 0x%lx-0x%lx\n",
miro->aci_port, miro->aci_port+2);
aci->aci_port, aci->aci_port+2);
snd_iprintf(buffer, " wss : 0x%x\n", wss);
snd_iprintf(buffer, " ide : 0x%x\n", ide);
snd_iprintf(buffer, " solomode: 0x%x\n", miro->aci_solomode);
snd_iprintf(buffer, " amp : 0x%x\n", miro->aci_amp);
snd_iprintf(buffer, " preamp : 0x%x\n", miro->aci_preamp);
snd_iprintf(buffer, " solomode: 0x%x\n", aci->aci_solomode);
snd_iprintf(buffer, " amp : 0x%x\n", aci->aci_amp);
snd_iprintf(buffer, " preamp : 0x%x\n", aci->aci_preamp);
}
static void __devinit snd_miro_proc_init(struct snd_card *card,
@ -1139,46 +1170,53 @@ static int __devinit snd_card_miro_detect(struct snd_card *card,
}
static int __devinit snd_card_miro_aci_detect(struct snd_card *card,
struct snd_miro * miro)
struct snd_miro *miro)
{
unsigned char regval;
int i;
struct snd_miro_aci *aci = &aci_device;
mutex_init(&miro->aci_mutex);
miro->aci = aci;
mutex_init(&aci->aci_mutex);
/* get ACI port from OPTi9xx MC 4 */
regval=inb(miro->mc_base + 4);
miro->aci_port = (regval & 0x10) ? 0x344: 0x354;
aci->aci_port = (regval & 0x10) ? 0x344 : 0x354;
if ((miro->res_aci_port = request_region(miro->aci_port, 3, "miro aci")) == NULL) {
miro->res_aci_port = request_region(aci->aci_port, 3, "miro aci");
if (miro->res_aci_port == NULL) {
snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n",
miro->aci_port, miro->aci_port+2);
aci->aci_port, aci->aci_port+2);
return -ENOMEM;
}
/* force ACI into a known state */
for (i = 0; i < 3; i++)
if (aci_cmd(miro, ACI_ERROR_OP, -1, -1) < 0) {
if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) {
snd_printk(KERN_ERR "can't force aci into known state.\n");
return -ENXIO;
}
if ((miro->aci_vendor=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0 ||
(miro->aci_product=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0) {
snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", miro->aci_port);
aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
if (aci->aci_vendor < 0 || aci->aci_product < 0) {
snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n",
aci->aci_port);
return -ENXIO;
}
if ((miro->aci_version=aci_cmd(miro, ACI_READ_VERSION, -1, -1)) < 0) {
aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1);
if (aci->aci_version < 0) {
snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n",
miro->aci_port);
aci->aci_port);
return -ENXIO;
}
if (aci_cmd(miro, ACI_INIT, -1, -1) < 0 ||
aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 ||
snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
snd_printk(KERN_ERR "can't initialize aci.\n");
return -ENXIO;
}
@ -1191,6 +1229,8 @@ static void snd_card_miro_free(struct snd_card *card)
struct snd_miro *miro = card->private_data;
release_and_free_resource(miro->res_aci_port);
if (miro->aci)
miro->aci->aci_port = 0;
release_and_free_resource(miro->res_mc_base);
}
@ -1250,7 +1290,6 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
}
miro->wss_base = port;
miro->mpu_port = mpu_port;
miro->irq = irq;
miro->mpu_irq = mpu_irq;
miro->dma1 = dma1;
@ -1272,6 +1311,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
return -EBUSY;
}
}
miro->mpu_port = mpu_port;
if (miro->irq == SNDRV_AUTO_IRQ) {
if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
snd_card_free(card);
@ -1339,9 +1380,9 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
return error;
}
if (miro->aci_vendor == 'm') {
if (miro->aci->aci_vendor == 'm') {
/* It looks like a miro sound card. */
switch (miro->aci_product) {
switch (miro->aci->aci_product) {
case 'A':
sprintf(card->shortname,
"miroSOUND PCM1 pro / PCM12");