aboutsummaryrefslogtreecommitdiff
path: root/sound/usb/6fire
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/6fire')
-rw-r--r--sound/usb/6fire/chip.c24
-rw-r--r--sound/usb/6fire/chip.h1
-rw-r--r--sound/usb/6fire/comm.c48
-rw-r--r--sound/usb/6fire/comm.h5
-rw-r--r--sound/usb/6fire/common.h1
-rw-r--r--sound/usb/6fire/control.c349
-rw-r--r--sound/usb/6fire/control.h9
-rw-r--r--sound/usb/6fire/firmware.c82
-rw-r--r--sound/usb/6fire/firmware.h2
-rw-r--r--sound/usb/6fire/midi.c31
-rw-r--r--sound/usb/6fire/midi.h9
-rw-r--r--sound/usb/6fire/pcm.c126
-rw-r--r--sound/usb/6fire/pcm.h5
13 files changed, 517 insertions, 175 deletions
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
index 8af92e3e9c1..dcddfc354ba 100644
--- a/sound/usb/6fire/chip.c
+++ b/sound/usb/6fire/chip.c
@@ -5,7 +5,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -29,9 +28,9 @@
#include <sound/initval.h>
MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>");
-MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0");
+MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver");
MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
+MODULE_SUPPORTED_DEVICE("{{TerraTec,DMX 6Fire USB}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
@@ -83,8 +82,8 @@ static void usb6fire_chip_destroy(struct sfire_chip *chip)
}
}
-static int __devinit usb6fire_chip_probe(struct usb_interface *intf,
- const struct usb_device_id *usb_id)
+static int usb6fire_chip_probe(struct usb_interface *intf,
+ const struct usb_device_id *usb_id)
{
int ret;
int i;
@@ -102,12 +101,12 @@ static int __devinit usb6fire_chip_probe(struct usb_interface *intf,
usb_set_intfdata(intf, chips[i]);
mutex_unlock(&register_mutex);
return 0;
- } else if (regidx < 0)
+ } else if (!devices[i] && regidx < 0)
regidx = i;
}
if (regidx < 0) {
mutex_unlock(&register_mutex);
- snd_printk(KERN_ERR PREFIX "too many cards registered.\n");
+ dev_err(&intf->dev, "too many cards registered.\n");
return -ENODEV;
}
devices[regidx] = device;
@@ -122,20 +121,19 @@ static int __devinit usb6fire_chip_probe(struct usb_interface *intf,
/* if we are here, card can be registered in alsa. */
if (usb_set_interface(device, 0, 0) != 0) {
- snd_printk(KERN_ERR PREFIX "can't set first interface.\n");
+ dev_err(&intf->dev, "can't set first interface.\n");
return -EIO;
}
- ret = snd_card_create(index[regidx], id[regidx], THIS_MODULE,
- sizeof(struct sfire_chip), &card);
+ ret = snd_card_new(&intf->dev, index[regidx], id[regidx],
+ THIS_MODULE, sizeof(struct sfire_chip), &card);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "cannot create alsa card.\n");
+ dev_err(&intf->dev, "cannot create alsa card.\n");
return ret;
}
strcpy(card->driver, "6FireUSB");
strcpy(card->shortname, "TerraTec DMX6FireUSB");
sprintf(card->longname, "%s at %d:%d", card->shortname,
device->bus->busnum, device->devnum);
- snd_card_set_dev(card, &intf->dev);
chip = card->private_data;
chips[regidx] = chip;
@@ -170,7 +168,7 @@ static int __devinit usb6fire_chip_probe(struct usb_interface *intf,
ret = snd_card_register(card);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "cannot register card.");
+ dev_err(&intf->dev, "cannot register card.");
usb6fire_chip_destroy(chip);
return ret;
}
diff --git a/sound/usb/6fire/chip.h b/sound/usb/6fire/chip.h
index d11e5cb520f..bde02d105a5 100644
--- a/sound/usb/6fire/chip.h
+++ b/sound/usb/6fire/chip.h
@@ -3,7 +3,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
index c994daa57af..161215d78d9 100644
--- a/sound/usb/6fire/comm.c
+++ b/sound/usb/6fire/comm.c
@@ -5,7 +5,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -52,7 +51,7 @@ static void usb6fire_comm_receiver_handler(struct urb *urb)
urb->status = 0;
urb->actual_length = 0;
if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
- snd_printk(KERN_WARNING PREFIX
+ dev_warn(&urb->dev->dev,
"comm data receiver aborted.\n");
}
}
@@ -111,31 +110,56 @@ static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)
static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,
u8 reg, u8 value)
{
- u8 buffer[13]; /* 13: maximum length of message */
+ u8 *buffer;
+ int ret;
+
+ /* 13: maximum length of message */
+ buffer = kmalloc(13, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
- return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+ ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+
+ kfree(buffer);
+ return ret;
}
static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
u8 reg, u8 vl, u8 vh)
{
- u8 buffer[13]; /* 13: maximum length of message */
+ u8 *buffer;
+ int ret;
+
+ /* 13: maximum length of message */
+ buffer = kmalloc(13, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
- return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+ ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+
+ kfree(buffer);
+ return ret;
}
-int __devinit usb6fire_comm_init(struct sfire_chip *chip)
+int usb6fire_comm_init(struct sfire_chip *chip)
{
struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
GFP_KERNEL);
- struct urb *urb = &rt->receiver;
+ struct urb *urb;
int ret;
if (!rt)
return -ENOMEM;
+ rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);
+ if (!rt->receiver_buffer) {
+ kfree(rt);
+ return -ENOMEM;
+ }
+
+ urb = &rt->receiver;
rt->serial = 1;
rt->chip = chip;
usb_init_urb(urb);
@@ -153,8 +177,9 @@ int __devinit usb6fire_comm_init(struct sfire_chip *chip)
urb->interval = 1;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0) {
+ kfree(rt->receiver_buffer);
kfree(rt);
- snd_printk(KERN_ERR PREFIX "cannot create comm data receiver.");
+ dev_err(&chip->dev->dev, "cannot create comm data receiver.");
return ret;
}
chip->comm = rt;
@@ -171,6 +196,9 @@ void usb6fire_comm_abort(struct sfire_chip *chip)
void usb6fire_comm_destroy(struct sfire_chip *chip)
{
- kfree(chip->comm);
+ struct comm_runtime *rt = chip->comm;
+
+ kfree(rt->receiver_buffer);
+ kfree(rt);
chip->comm = NULL;
}
diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h
index edc5dc84b88..780d5ed8e5d 100644
--- a/sound/usb/6fire/comm.h
+++ b/sound/usb/6fire/comm.h
@@ -3,7 +3,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +24,7 @@ struct comm_runtime {
struct sfire_chip *chip;
struct urb receiver;
- u8 receiver_buffer[COMM_RECEIVER_BUFSIZE];
+ u8 *receiver_buffer;
u8 serial; /* urb serial */
@@ -37,7 +36,7 @@ struct comm_runtime {
u8 vh, u8 vl);
};
-int __devinit usb6fire_comm_init(struct sfire_chip *chip);
+int usb6fire_comm_init(struct sfire_chip *chip);
void usb6fire_comm_abort(struct sfire_chip *chip);
void usb6fire_comm_destroy(struct sfire_chip *chip);
#endif /* USB6FIRE_COMM_H */
diff --git a/sound/usb/6fire/common.h b/sound/usb/6fire/common.h
index 7dbeb4a3783..b6eb03ed1c2 100644
--- a/sound/usb/6fire/common.h
+++ b/sound/usb/6fire/common.h
@@ -3,7 +3,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
index ac828eff1a6..184e3987ac2 100644
--- a/sound/usb/6fire/control.c
+++ b/sound/usb/6fire/control.c
@@ -5,9 +5,12 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
+ * Thanks to:
+ * - Holger Ruckdeschel: he found out how to control individual channel
+ * volumes and introduced mute switch
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -16,6 +19,7 @@
#include <linux/interrupt.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include "control.h"
#include "comm.h"
@@ -25,26 +29,6 @@ static char *opt_coax_texts[2] = { "Optical", "Coax" };
static char *line_phono_texts[2] = { "Line", "Phono" };
/*
- * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$
- * this is done because the linear values cause rapid degredation
- * of volume in the uppermost region.
- */
-static const u8 log_volume_table[128] = {
- 0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34,
- 0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43,
- 0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
- 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56,
- 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c,
- 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62,
- 0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68,
- 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c,
- 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71,
- 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75,
- 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79,
- 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c,
- 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f };
-
-/*
* data that needs to be sent to device. sets up card internal stuff.
* values dumped from windows driver and filtered by trial'n'error.
*/
@@ -59,7 +43,7 @@ init_data[] = {
{ 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
{ 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
{ 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
- { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
+ { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
{ 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
{ 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
{ 0 } /* TERMINATING ENTRY */
@@ -70,20 +54,47 @@ static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
+static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0);
+static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500);
+
enum {
DIGITAL_THRU_ONLY_SAMPLERATE = 3
};
-static void usb6fire_control_master_vol_update(struct control_runtime *rt)
+static void usb6fire_control_output_vol_update(struct control_runtime *rt)
{
struct comm_runtime *comm_rt = rt->chip->comm;
- if (comm_rt) {
- /* set volume */
- comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f -
- log_volume_table[rt->master_vol]);
- /* unmute */
- comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00);
- }
+ int i;
+
+ if (comm_rt)
+ for (i = 0; i < 6; i++)
+ if (!(rt->ovol_updated & (1 << i))) {
+ comm_rt->write8(comm_rt, 0x12, 0x0f + i,
+ 180 - rt->output_vol[i]);
+ rt->ovol_updated |= 1 << i;
+ }
+}
+
+static void usb6fire_control_output_mute_update(struct control_runtime *rt)
+{
+ struct comm_runtime *comm_rt = rt->chip->comm;
+
+ if (comm_rt)
+ comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute);
+}
+
+static void usb6fire_control_input_vol_update(struct control_runtime *rt)
+{
+ struct comm_runtime *comm_rt = rt->chip->comm;
+ int i;
+
+ if (comm_rt)
+ for (i = 0; i < 2; i++)
+ if (!(rt->ivol_updated & (1 << i))) {
+ comm_rt->write8(comm_rt, 0x12, 0x1c + i,
+ rt->input_vol[i] & 0x3f);
+ rt->ivol_updated |= 1 << i;
+ }
}
static void usb6fire_control_line_phono_update(struct control_runtime *rt)
@@ -165,34 +176,151 @@ static int usb6fire_control_streaming_update(struct control_runtime *rt)
return -EINVAL;
}
-static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
+static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
+ uinfo->count = 2;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 127;
+ uinfo->value.integer.max = 180;
return 0;
}
-static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol,
+static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ unsigned int ch = kcontrol->private_value;
int changed = 0;
- if (rt->master_vol != ucontrol->value.integer.value[0]) {
- rt->master_vol = ucontrol->value.integer.value[0];
- usb6fire_control_master_vol_update(rt);
+
+ if (ch > 4) {
+ dev_err(&rt->chip->dev->dev,
+ "Invalid channel in volume control.");
+ return -EINVAL;
+ }
+
+ if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) {
+ rt->output_vol[ch] = ucontrol->value.integer.value[0];
+ rt->ovol_updated &= ~(1 << ch);
changed = 1;
}
+ if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) {
+ rt->output_vol[ch + 1] = ucontrol->value.integer.value[1];
+ rt->ovol_updated &= ~(2 << ch);
+ changed = 1;
+ }
+
+ if (changed)
+ usb6fire_control_output_vol_update(rt);
+
return changed;
}
-static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol,
+static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = rt->master_vol;
+ unsigned int ch = kcontrol->private_value;
+
+ if (ch > 4) {
+ dev_err(&rt->chip->dev->dev,
+ "Invalid channel in volume control.");
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] = rt->output_vol[ch];
+ ucontrol->value.integer.value[1] = rt->output_vol[ch + 1];
+ return 0;
+}
+
+static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ unsigned int ch = kcontrol->private_value;
+ u8 old = rt->output_mute;
+ u8 value = 0;
+
+ if (ch > 4) {
+ dev_err(&rt->chip->dev->dev,
+ "Invalid channel in volume control.");
+ return -EINVAL;
+ }
+
+ rt->output_mute &= ~(3 << ch);
+ if (ucontrol->value.integer.value[0])
+ value |= 1;
+ if (ucontrol->value.integer.value[1])
+ value |= 2;
+ rt->output_mute |= value << ch;
+
+ if (rt->output_mute != old)
+ usb6fire_control_output_mute_update(rt);
+
+ return rt->output_mute != old;
+}
+
+static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ unsigned int ch = kcontrol->private_value;
+ u8 value = rt->output_mute >> ch;
+
+ if (ch > 4) {
+ dev_err(&rt->chip->dev->dev,
+ "Invalid channel in volume control.");
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] = 1 & value;
+ value >>= 1;
+ ucontrol->value.integer.value[1] = 1 & value;
+
+ return 0;
+}
+
+static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 30;
+ return 0;
+}
+
+static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+
+ if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
+ rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
+ rt->ivol_updated &= ~(1 << 0);
+ changed = 1;
+ }
+ if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
+ rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
+ rt->ivol_updated &= ~(1 << 1);
+ changed = 1;
+ }
+
+ if (changed)
+ usb6fire_control_input_vol_update(rt);
+
+ return changed;
+}
+
+static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = rt->input_vol[0] + 15;
+ ucontrol->value.integer.value[1] = rt->input_vol[1] + 15;
+
return 0;
}
@@ -287,18 +415,83 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct __devinitdata snd_kcontrol_new elements[] = {
+static struct snd_kcontrol_new vol_elements[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Volume",
+ .name = "Analog Playback Volume",
.index = 0,
+ .private_value = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = usb6fire_control_output_vol_info,
+ .get = usb6fire_control_output_vol_get,
+ .put = usb6fire_control_output_vol_put,
+ .tlv = { .p = tlv_output }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Playback Volume",
+ .index = 1,
+ .private_value = 2,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = usb6fire_control_output_vol_info,
+ .get = usb6fire_control_output_vol_get,
+ .put = usb6fire_control_output_vol_put,
+ .tlv = { .p = tlv_output }
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Playback Volume",
+ .index = 2,
+ .private_value = 4,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = usb6fire_control_output_vol_info,
+ .get = usb6fire_control_output_vol_get,
+ .put = usb6fire_control_output_vol_put,
+ .tlv = { .p = tlv_output }
+ },
+ {}
+};
+
+static struct snd_kcontrol_new mute_elements[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Playback Switch",
+ .index = 0,
+ .private_value = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_ctl_boolean_stereo_info,
+ .get = usb6fire_control_output_mute_get,
+ .put = usb6fire_control_output_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Playback Switch",
+ .index = 1,
+ .private_value = 2,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = usb6fire_control_master_vol_info,
- .get = usb6fire_control_master_vol_get,
- .put = usb6fire_control_master_vol_put
+ .info = snd_ctl_boolean_stereo_info,
+ .get = usb6fire_control_output_mute_get,
+ .put = usb6fire_control_output_mute_put,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Playback Switch",
+ .index = 2,
+ .private_value = 4,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_ctl_boolean_stereo_info,
+ .get = usb6fire_control_output_mute_get,
+ .put = usb6fire_control_output_mute_put,
+ },
+ {}
+};
+
+static struct snd_kcontrol_new elements[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Line/Phono Capture Route",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -324,10 +517,55 @@ static struct __devinitdata snd_kcontrol_new elements[] = {
.get = usb6fire_control_digital_thru_get,
.put = usb6fire_control_digital_thru_put
},
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Capture Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = usb6fire_control_input_vol_info,
+ .get = usb6fire_control_input_vol_get,
+ .put = usb6fire_control_input_vol_put,
+ .tlv = { .p = tlv_input }
+ },
{}
};
-int __devinit usb6fire_control_init(struct sfire_chip *chip)
+static int usb6fire_control_add_virtual(
+ struct control_runtime *rt,
+ struct snd_card *card,
+ char *name,
+ struct snd_kcontrol_new *elems)
+{
+ int ret;
+ int i;
+ struct snd_kcontrol *vmaster =
+ snd_ctl_make_virtual_master(name, tlv_output);
+ struct snd_kcontrol *control;
+
+ if (!vmaster)
+ return -ENOMEM;
+ ret = snd_ctl_add(card, vmaster);
+ if (ret < 0)
+ return ret;
+
+ i = 0;
+ while (elems[i].name) {
+ control = snd_ctl_new1(&elems[i], rt);
+ if (!control)
+ return -ENOMEM;
+ ret = snd_ctl_add(card, control);
+ if (ret < 0)
+ return ret;
+ ret = snd_ctl_add_slave(vmaster, control);
+ if (ret < 0)
+ return ret;
+ i++;
+ }
+ return 0;
+}
+
+int usb6fire_control_init(struct sfire_chip *chip)
{
int i;
int ret;
@@ -352,15 +590,32 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip)
usb6fire_control_opt_coax_update(rt);
usb6fire_control_line_phono_update(rt);
- usb6fire_control_master_vol_update(rt);
+ usb6fire_control_output_vol_update(rt);
+ usb6fire_control_output_mute_update(rt);
+ usb6fire_control_input_vol_update(rt);
usb6fire_control_streaming_update(rt);
+ ret = usb6fire_control_add_virtual(rt, chip->card,
+ "Master Playback Volume", vol_elements);
+ if (ret) {
+ dev_err(&chip->dev->dev, "cannot add control.\n");
+ kfree(rt);
+ return ret;
+ }
+ ret = usb6fire_control_add_virtual(rt, chip->card,
+ "Master Playback Switch", mute_elements);
+ if (ret) {
+ dev_err(&chip->dev->dev, "cannot add control.\n");
+ kfree(rt);
+ return ret;
+ }
+
i = 0;
while (elements[i].name) {
ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
if (ret < 0) {
kfree(rt);
- snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+ dev_err(&chip->dev->dev, "cannot add control.\n");
return ret;
}
i++;
diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h
index 8f5aeead2e3..5a40ba14348 100644
--- a/sound/usb/6fire/control.h
+++ b/sound/usb/6fire/control.h
@@ -3,7 +3,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -44,10 +43,14 @@ struct control_runtime {
bool line_phono_switch;
bool digital_thru_switch;
bool usb_streaming;
- u8 master_vol;
+ u8 output_vol[6];
+ u8 ovol_updated;
+ u8 output_mute;
+ s8 input_vol[2];
+ u8 ivol_updated;
};
-int __devinit usb6fire_control_init(struct sfire_chip *chip);
+int usb6fire_control_init(struct sfire_chip *chip);
void usb6fire_control_abort(struct sfire_chip *chip);
void usb6fire_control_destroy(struct sfire_chip *chip);
#endif /* USB6FIRE_CONTROL_H */
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 3b5f517a397..3b02e54b8f6 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -5,7 +5,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -43,8 +42,8 @@ static const u8 ep_w_max_packet_size[] = {
0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
};
-static const u8 known_fw_versions[][4] = {
- { 0x03, 0x01, 0x0b, 0x00 }
+static const u8 known_fw_versions[][2] = {
+ { 0x03, 0x01 }
};
struct ihex_record {
@@ -210,7 +209,7 @@ static int usb6fire_fw_ezusb_upload(
int ret;
u8 data;
struct usb_device *device = interface_to_usbdev(intf);
- const struct firmware *fw = 0;
+ const struct firmware *fw = NULL;
struct ihex_record *rec = kmalloc(sizeof(struct ihex_record),
GFP_KERNEL);
@@ -220,16 +219,16 @@ static int usb6fire_fw_ezusb_upload(
ret = request_firmware(&fw, fwname, &device->dev);
if (ret < 0) {
kfree(rec);
- snd_printk(KERN_ERR PREFIX "error requesting ezusb "
- "firmware %s.\n", fwname);
+ dev_err(&intf->dev,
+ "error requesting ezusb firmware %s.\n", fwname);
return ret;
}
ret = usb6fire_fw_ihex_init(fw, rec);
if (ret < 0) {
kfree(rec);
release_firmware(fw);
- snd_printk(KERN_ERR PREFIX "error validating ezusb "
- "firmware %s.\n", fwname);
+ dev_err(&intf->dev,
+ "error validating ezusb firmware %s.\n", fwname);
return ret;
}
/* upload firmware image */
@@ -238,8 +237,9 @@ static int usb6fire_fw_ezusb_upload(
if (ret < 0) {
kfree(rec);
release_firmware(fw);
- snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
- "firmware %s: begin message.\n", fwname);
+ dev_err(&intf->dev,
+ "unable to upload ezusb firmware %s: begin message.\n",
+ fwname);
return ret;
}
@@ -249,8 +249,9 @@ static int usb6fire_fw_ezusb_upload(
if (ret < 0) {
kfree(rec);
release_firmware(fw);
- snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
- "firmware %s: data urb.\n", fwname);
+ dev_err(&intf->dev,
+ "unable to upload ezusb firmware %s: data urb.\n",
+ fwname);
return ret;
}
}
@@ -261,8 +262,9 @@ static int usb6fire_fw_ezusb_upload(
ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
postdata, postlen);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
- "firmware %s: post urb.\n", fwname);
+ dev_err(&intf->dev,
+ "unable to upload ezusb firmware %s: post urb.\n",
+ fwname);
return ret;
}
}
@@ -270,8 +272,9 @@ static int usb6fire_fw_ezusb_upload(
data = 0x00; /* resume ezusb cpu */
ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
- "firmware %s: end message.\n", fwname);
+ dev_err(&intf->dev,
+ "unable to upload ezusb firmware %s: end message.\n",
+ fwname);
return ret;
}
return 0;
@@ -293,7 +296,7 @@ static int usb6fire_fw_fpga_upload(
ret = request_firmware(&fw, fwname, &device->dev);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to get fpga firmware %s.\n",
+ dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
fwname);
kfree(buffer);
return -EIO;
@@ -306,8 +309,8 @@ static int usb6fire_fw_fpga_upload(
if (ret < 0) {
kfree(buffer);
release_firmware(fw);
- snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
- "begin urb.\n");
+ dev_err(&intf->dev,
+ "unable to upload fpga firmware: begin urb.\n");
return ret;
}
@@ -319,8 +322,8 @@ static int usb6fire_fw_fpga_upload(
if (ret < 0) {
release_firmware(fw);
kfree(buffer);
- snd_printk(KERN_ERR PREFIX "unable to upload fpga "
- "firmware: fw urb.\n");
+ dev_err(&intf->dev,
+ "unable to upload fpga firmware: fw urb.\n");
return ret;
}
}
@@ -329,8 +332,8 @@ static int usb6fire_fw_fpga_upload(
ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
- "end urb.\n");
+ dev_err(&intf->dev,
+ "unable to upload fpga firmware: end urb.\n");
return ret;
}
return 0;
@@ -339,19 +342,18 @@ static int usb6fire_fw_fpga_upload(
/* check, if the firmware version the devices has currently loaded
* is known by this driver. 'version' needs to have 4 bytes version
* info data. */
-static int usb6fire_fw_check(u8 *version)
+static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version)
{
int i;
for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
- if (!memcmp(version, known_fw_versions + i, 4))
+ if (!memcmp(version, known_fw_versions + i, 2))
return 0;
- snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
- "%02x %02x %02x %02x. "
+ dev_err(&intf->dev, "invalid fimware version in device: %4ph. "
"please reconnect to power. if this failure "
"still happens, check your firmware installation.",
- version[0], version[1], version[2], version[3]);
+ version);
return -EINVAL;
}
@@ -366,16 +368,16 @@ int usb6fire_fw_init(struct usb_interface *intf)
ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to receive device "
- "firmware state.\n");
+ dev_err(&intf->dev,
+ "unable to receive device firmware state.\n");
return ret;
}
if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
- snd_printk(KERN_ERR PREFIX "unknown device firmware state "
- "received from device: ");
+ dev_err(&intf->dev,
+ "unknown device firmware state received from device:");
for (i = 0; i < 8; i++)
- snd_printk("%02x ", buffer[i]);
- snd_printk("\n");
+ printk(KERN_CONT "%02x ", buffer[i]);
+ printk(KERN_CONT "\n");
return -EIO;
}
/* do we need fpga loader ezusb firmware? */
@@ -388,7 +390,7 @@ int usb6fire_fw_init(struct usb_interface *intf)
}
/* do we need fpga firmware and application ezusb firmware? */
else if (buffer[3] == 0x02) {
- ret = usb6fire_fw_check(buffer + 4);
+ ret = usb6fire_fw_check(intf, buffer + 4);
if (ret < 0)
return ret;
ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
@@ -404,14 +406,14 @@ int usb6fire_fw_init(struct usb_interface *intf)
}
/* all fw loaded? */
else if (buffer[3] == 0x03)
- return usb6fire_fw_check(buffer + 4);
+ return usb6fire_fw_check(intf, buffer + 4);
/* unknown data? */
else {
- snd_printk(KERN_ERR PREFIX "unknown device firmware state "
- "received from device: ");
+ dev_err(&intf->dev,
+ "unknown device firmware state received from device: ");
for (i = 0; i < 8; i++)
- snd_printk("%02x ", buffer[i]);
- snd_printk("\n");
+ printk(KERN_CONT "%02x ", buffer[i]);
+ printk(KERN_CONT "\n");
return -EIO;
}
return 0;
diff --git a/sound/usb/6fire/firmware.h b/sound/usb/6fire/firmware.h
index 00856989538..c109c4f75ab 100644
--- a/sound/usb/6fire/firmware.h
+++ b/sound/usb/6fire/firmware.h
@@ -22,6 +22,6 @@ enum /* firmware state of device */
FW_NOT_READY = 1
};
-int __devinit usb6fire_fw_init(struct usb_interface *intf);
+int usb6fire_fw_init(struct usb_interface *intf);
#endif /* USB6FIRE_FIRMWARE_H */
diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c
index 13f4509dce2..3d410969553 100644
--- a/sound/usb/6fire/midi.c
+++ b/sound/usb/6fire/midi.c
@@ -5,7 +5,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +19,10 @@
#include "chip.h"
#include "comm.h"
+enum {
+ MIDI_BUFSIZE = 64
+};
+
static void usb6fire_midi_out_handler(struct urb *urb)
{
struct midi_runtime *rt = urb->context;
@@ -38,8 +41,9 @@ static void usb6fire_midi_out_handler(struct urb *urb)
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0)
- snd_printk(KERN_ERR PREFIX "midi out urb "
- "submit failed: %d\n", ret);
+ dev_err(&urb->dev->dev,
+ "midi out urb submit failed: %d\n",
+ ret);
} else /* no more data to transmit */
rt->out = NULL;
}
@@ -91,8 +95,9 @@ static void usb6fire_midi_out_trigger(
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0)
- snd_printk(KERN_ERR PREFIX "midi out urb "
- "submit failed: %d\n", ret);
+ dev_err(&urb->dev->dev,
+ "midi out urb submit failed: %d\n",
+ ret);
else
rt->out = alsa_sub;
}
@@ -147,7 +152,7 @@ static struct snd_rawmidi_ops in_ops = {
.trigger = usb6fire_midi_in_trigger
};
-int __devinit usb6fire_midi_init(struct sfire_chip *chip)
+int usb6fire_midi_init(struct sfire_chip *chip)
{
int ret;
struct midi_runtime *rt = kzalloc(sizeof(struct midi_runtime),
@@ -157,6 +162,12 @@ int __devinit usb6fire_midi_init(struct sfire_chip *chip)
if (!rt)
return -ENOMEM;
+ rt->out_buffer = kzalloc(MIDI_BUFSIZE, GFP_KERNEL);
+ if (!rt->out_buffer) {
+ kfree(rt);
+ return -ENOMEM;
+ }
+
rt->chip = chip;
rt->in_received = usb6fire_midi_in_received;
rt->out_buffer[0] = 0x80; /* 'send midi' command */
@@ -170,8 +181,9 @@ int __devinit usb6fire_midi_init(struct sfire_chip *chip)
ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance);
if (ret < 0) {
+ kfree(rt->out_buffer);
kfree(rt);
- snd_printk(KERN_ERR PREFIX "unable to create midi.\n");
+ dev_err(&chip->dev->dev, "unable to create midi.\n");
return ret;
}
rt->instance->private_data = rt;
@@ -198,6 +210,9 @@ void usb6fire_midi_abort(struct sfire_chip *chip)
void usb6fire_midi_destroy(struct sfire_chip *chip)
{
- kfree(chip->midi);
+ struct midi_runtime *rt = chip->midi;
+
+ kfree(rt->out_buffer);
+ kfree(rt);
chip->midi = NULL;
}
diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h
index 97a7bf66913..84851b9f555 100644
--- a/sound/usb/6fire/midi.h
+++ b/sound/usb/6fire/midi.h
@@ -3,7 +3,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -17,10 +16,6 @@
#include "common.h"
-enum {
- MIDI_BUFSIZE = 64
-};
-
struct midi_runtime {
struct sfire_chip *chip;
struct snd_rawmidi *instance;
@@ -33,13 +28,13 @@ struct midi_runtime {
struct snd_rawmidi_substream *out;
struct urb out_urb;
u8 out_serial; /* serial number of out packet */
- u8 out_buffer[MIDI_BUFSIZE];
+ u8 *out_buffer;
int buffer_offset;
void (*in_received)(struct midi_runtime *rt, u8 *data, int length);
};
-int __devinit usb6fire_midi_init(struct sfire_chip *chip);
+int usb6fire_midi_init(struct sfire_chip *chip);
void usb6fire_midi_abort(struct sfire_chip *chip);
void usb6fire_midi_destroy(struct sfire_chip *chip);
#endif /* USB6FIRE_MIDI_H */
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index d144cdb2f15..ba40489b2de 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -5,7 +5,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -80,32 +79,35 @@ static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
ctrl_rt->usb_streaming = false;
ret = ctrl_rt->update_streaming(ctrl_rt);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "error stopping streaming while "
- "setting samplerate %d.\n", rates[rt->rate]);
+ dev_err(&rt->chip->dev->dev,
+ "error stopping streaming while setting samplerate %d.\n",
+ rates[rt->rate]);
return ret;
}
ret = ctrl_rt->set_rate(ctrl_rt, rt->rate);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n",
- rates[rt->rate]);
+ dev_err(&rt->chip->dev->dev,
+ "error setting samplerate %d.\n",
+ rates[rt->rate]);
return ret;
}
ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS,
false, false);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "error initializing channels "
- "while setting samplerate %d.\n",
- rates[rt->rate]);
+ dev_err(&rt->chip->dev->dev,
+ "error initializing channels while setting samplerate %d.\n",
+ rates[rt->rate]);
return ret;
}
ctrl_rt->usb_streaming = true;
ret = ctrl_rt->update_streaming(ctrl_rt);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "error starting streaming while "
- "setting samplerate %d.\n", rates[rt->rate]);
+ dev_err(&rt->chip->dev->dev,
+ "error starting streaming while setting samplerate %d.\n",
+ rates[rt->rate]);
return ret;
}
@@ -125,7 +127,7 @@ static struct pcm_substream *usb6fire_pcm_get_substream(
return &rt->playback;
else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE)
return &rt->capture;
- snd_printk(KERN_ERR PREFIX "error getting pcm substream slot.\n");
+ dev_err(&rt->chip->dev->dev, "error getting pcm substream slot.\n");
return NULL;
}
@@ -136,6 +138,9 @@ static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
struct control_runtime *ctrl_rt = rt->chip->control;
if (rt->stream_state != STREAM_DISABLED) {
+
+ rt->stream_state = STREAM_STOPPING;
+
for (i = 0; i < PCM_N_URBS; i++) {
usb_kill_urb(&rt->in_urbs[i].instance);
usb_kill_urb(&rt->out_urbs[i].instance);
@@ -255,7 +260,7 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub,
else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
dest = (u32 *) (urb->buffer);
else {
- snd_printk(KERN_ERR PREFIX "Unknown sample format.");
+ dev_err(&rt->chip->dev->dev, "Unknown sample format.");
return;
}
@@ -305,8 +310,8 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
}
if (rt->stream_state == STREAM_DISABLED) {
- snd_printk(KERN_ERR PREFIX "internal error: "
- "stream disabled in in-urb handler.\n");
+ dev_err(&rt->chip->dev->dev,
+ "internal error: stream disabled in in-urb handler.\n");
return;
}
@@ -408,7 +413,7 @@ static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub)
if (!sub) {
mutex_unlock(&rt->stream_mutex);
- snd_printk(KERN_ERR PREFIX "invalid stream type.\n");
+ dev_err(&rt->chip->dev->dev, "invalid stream type.\n");
return -EINVAL;
}
@@ -448,13 +453,13 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)
static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
struct snd_pcm_hw_params *hw_params)
{
- return snd_pcm_lib_malloc_pages(alsa_sub,
- params_buffer_bytes(hw_params));
+ return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub,
+ params_buffer_bytes(hw_params));
}
static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
{
- return snd_pcm_lib_free_pages(alsa_sub);
+ return snd_pcm_lib_free_vmalloc_buffer(alsa_sub);
}
static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
@@ -479,8 +484,9 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
break;
if (rt->rate == ARRAY_SIZE(rates)) {
mutex_unlock(&rt->stream_mutex);
- snd_printk("invalid rate %d in prepare.\n",
- alsa_rt->rate);
+ dev_err(&rt->chip->dev->dev,
+ "invalid rate %d in prepare.\n",
+ alsa_rt->rate);
return -EINVAL;
}
@@ -492,8 +498,8 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
ret = usb6fire_pcm_stream_start(rt);
if (ret) {
mutex_unlock(&rt->stream_mutex);
- snd_printk(KERN_ERR PREFIX
- "could not start pcm stream.\n");
+ dev_err(&rt->chip->dev->dev,
+ "could not start pcm stream.\n");
return ret;
}
}
@@ -541,7 +547,7 @@ static snd_pcm_uframes_t usb6fire_pcm_pointer(
snd_pcm_uframes_t ret;
if (rt->panic || !sub)
- return SNDRV_PCM_STATE_XRUN;
+ return SNDRV_PCM_POS_XRUN;
spin_lock_irqsave(&sub->lock, flags);
ret = sub->dma_off;
@@ -558,11 +564,13 @@ static struct snd_pcm_ops pcm_ops = {
.prepare = usb6fire_pcm_prepare,
.trigger = usb6fire_pcm_trigger,
.pointer = usb6fire_pcm_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
};
-static void __devinit usb6fire_pcm_init_urb(struct pcm_urb *urb,
- struct sfire_chip *chip, bool in, int ep,
- void (*handler)(struct urb *))
+static void usb6fire_pcm_init_urb(struct pcm_urb *urb,
+ struct sfire_chip *chip, bool in, int ep,
+ void (*handler)(struct urb *))
{
urb->chip = chip;
usb_init_urb(&urb->instance);
@@ -573,13 +581,39 @@ static void __devinit usb6fire_pcm_init_urb(struct pcm_urb *urb,
urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep)
: usb_sndisocpipe(chip->dev, ep);
urb->instance.interval = 1;
- urb->instance.transfer_flags = URB_ISO_ASAP;
urb->instance.complete = handler;
urb->instance.context = urb;
urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB;
}
-int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
+static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt)
+{
+ int i;
+
+ for (i = 0; i < PCM_N_URBS; i++) {
+ rt->out_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB
+ * PCM_MAX_PACKET_SIZE, GFP_KERNEL);
+ if (!rt->out_urbs[i].buffer)
+ return -ENOMEM;
+ rt->in_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB
+ * PCM_MAX_PACKET_SIZE, GFP_KERNEL);
+ if (!rt->in_urbs[i].buffer)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt)
+{
+ int i;
+
+ for (i = 0; i < PCM_N_URBS; i++) {
+ kfree(rt->out_urbs[i].buffer);
+ kfree(rt->in_urbs[i].buffer);
+ }
+}
+
+int usb6fire_pcm_init(struct sfire_chip *chip)
{
int i;
int ret;
@@ -590,6 +624,13 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
if (!rt)
return -ENOMEM;
+ ret = usb6fire_pcm_buffers_init(rt);
+ if (ret) {
+ usb6fire_pcm_buffers_destroy(rt);
+ kfree(rt);
+ return ret;
+ }
+
rt->chip = chip;
rt->stream_state = STREAM_DISABLED;
rt->rate = ARRAY_SIZE(rates);
@@ -611,8 +652,9 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm);
if (ret < 0) {
+ usb6fire_pcm_buffers_destroy(rt);
kfree(rt);
- snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n");
+ dev_err(&chip->dev->dev, "cannot create pcm instance.\n");
return ret;
}
@@ -621,14 +663,11 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
- ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- MAX_BUFSIZE, MAX_BUFSIZE);
if (ret) {
+ usb6fire_pcm_buffers_destroy(rt);
kfree(rt);
- snd_printk(KERN_ERR PREFIX
- "error preallocating pcm buffers.\n");
+ dev_err(&chip->dev->dev,
+ "error preallocating pcm buffers.\n");
return ret;
}
rt->instance = pcm;
@@ -640,17 +679,25 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
void usb6fire_pcm_abort(struct sfire_chip *chip)
{
struct pcm_runtime *rt = chip->pcm;
+ unsigned long flags;
int i;
if (rt) {
rt->panic = true;
- if (rt->playback.instance)
+ if (rt->playback.instance) {
+ snd_pcm_stream_lock_irqsave(rt->playback.instance, flags);
snd_pcm_stop(rt->playback.instance,
SNDRV_PCM_STATE_XRUN);
- if (rt->capture.instance)
+ snd_pcm_stream_unlock_irqrestore(rt->playback.instance, flags);
+ }
+
+ if (rt->capture.instance) {
+ snd_pcm_stream_lock_irqsave(rt->capture.instance, flags);
snd_pcm_stop(rt->capture.instance,
SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock_irqrestore(rt->capture.instance, flags);
+ }
for (i = 0; i < PCM_N_URBS; i++) {
usb_poison_urb(&rt->in_urbs[i].instance);
@@ -662,6 +709,9 @@ void usb6fire_pcm_abort(struct sfire_chip *chip)
void usb6fire_pcm_destroy(struct sfire_chip *chip)
{
- kfree(chip->pcm);
+ struct pcm_runtime *rt = chip->pcm;
+
+ usb6fire_pcm_buffers_destroy(rt);
+ kfree(rt);
chip->pcm = NULL;
}
diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h
index 2bee8137400..f5779d6182c 100644
--- a/sound/usb/6fire/pcm.h
+++ b/sound/usb/6fire/pcm.h
@@ -3,7 +3,6 @@
*
* Author: Torsten Schenk <torsten.schenk@zoho.com>
* Created: Jan 01, 2011
- * Version: 0.3.0
* Copyright: (C) Torsten Schenk
*
* This program is free software; you can redistribute it and/or modify
@@ -33,7 +32,7 @@ struct pcm_urb {
struct urb instance;
struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB];
/* END DO NOT SEPARATE */
- u8 buffer[PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE];
+ u8 *buffer;
struct pcm_urb *peer;
};
@@ -70,7 +69,7 @@ struct pcm_runtime {
bool stream_wait_cond;
};
-int __devinit usb6fire_pcm_init(struct sfire_chip *chip);
+int usb6fire_pcm_init(struct sfire_chip *chip);
void usb6fire_pcm_abort(struct sfire_chip *chip);
void usb6fire_pcm_destroy(struct sfire_chip *chip);
#endif /* USB6FIRE_PCM_H */