Re: [Fwd: Scratch Live amplifier switch]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Takashi Iwai wrote:
> I'd recommend not to use put callback.  snd_kcontrol_value is a big
> struct, so it should be avoided to be used on the stack as much as
> possible.  Better to take the accessor part from the put callback and
> call it from here.
> 
> 
> Could you fix and repost?
I reworked the patch and it should be better now (with regards to
multiple issues).
As always - apply or complain :)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkrYzw0ACgkQWo5Cf7DM0R8/JQCdFVUojGczhdtqizcm809LSov+
ndMAoIkW0mL7Hq0bhj0N/FZxBunL2VO8
=2KbY
-----END PGP SIGNATURE-----
Signed-off-by: Andreas Bergmeier <andreas.bergmeier@xxxxxxx>

diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 00397c8..532d02d 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -2013,6 +2013,281 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
 	}
 }
 
+static void snd_usb_cleanup_interrupt_urb(struct urb *pUrb)
+{
+	if (pUrb->transfer_buffer_length > 0)
+		kfree(pUrb->transfer_buffer);
+
+	kfree(pUrb->context);
+
+	usb_free_urb(pUrb);
+}
+
+/* Wrapper for setting and submitting the interrupt urb().*/
+static int snd_usb_interrupt_trans(struct usb_device *dev,
+	unsigned int pipe, void *data, __u16 size, usb_complete_t callback)
+{
+	int err = 0;
+	void *buf = NULL;
+	struct urb *pUrb = NULL;
+
+	buf = kmemdup(data, size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	pUrb = usb_alloc_urb(1/*int iso packets*/, GFP_KERNEL);
+
+	if (!pUrb) {
+		/* cleanup */
+		kfree(buf);
+		return -ENOMEM;
+	}
+
+	/*TODO: Remove hardcoded 4*/
+	usb_fill_int_urb(pUrb, dev, pipe, buf, size, callback, NULL, 4);
+
+	err = usb_submit_urb(pUrb, GFP_KERNEL);
+
+	if (err < 0)
+		snd_usb_cleanup_interrupt_urb(pUrb);
+
+	return err;
+}
+
+#define snd_sl_phono_info snd_ctl_boolean_mono_info
+
+#define snd_sl_phono_receive snd_usb_cleanup_interrupt_urb
+
+#define snd_sl_phono_changed snd_sl_phono_receive
+
+static int snd_sl_phono_get(struct snd_kcontrol *kcontrol,
+	 struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = kcontrol->private_value;
+
+	/* the following code gets the value of the device
+	 * we just trust that the remembered state is correct
+	 * and don't use it :)
+
+	snd_usb_interrupt_trans(mixer->chip->dev,
+				usb_rcvbulkpipe(mixer->chip->dev, 0x83),
+				buffer, bufferSize, snd_sl_phono_receive);
+
+	unsigned char statusMessage[] = {7};
+
+	snd_usb_interrupt_trans(mixer->chip->dev,
+				usb_sndintpipe(mixer->chip->dev, 0x03),
+				statusMessage, 1, snd_sl_phono_receive);
+*/
+
+	return 0;
+}
+
+/* One example USB message on startup
+ * Unknown command
+	IN  03 Length: 0x40 ...
+	OUT 83 Length: 0x01 "00"
+	IN  03 Length: 0x40 "00 00 03 00 FF FF 02 00 01 00 03 00 01 00 FB FF
+		01 00 FF FF 06 00 02 00 FF FF 03 00 05 00 00 00
+		06 00 FC FF FD FF 03 00 FD FF 04 00 FB FF F8 FF
+		FC FF FD FF 06 00 01 00 01 00 FF FF 04 00 02 00"
+
+ * Sets line mode
+	IN  03 Length: 0x40 ...
+	OUT 83 Length: 0x02 "07 01"
+	IN  03 Length: 0x40 "07 FF 03 00 FF FF 02 00 01 00 03 00 01 00 FB FF
+		01 00 FF FF 06 00 02 00 FF FF 03 00 05 00 00 00
+		06 00 FC FF FD FF 03 00 FD FF 04 00 FB FF F8 FF
+		FC FF FD FF 06 00 01 00 01 00 FF FF 04 00 02 00"
+
+ * Unknown "termination" message?
+	IN  03 Length: 0x40 ...
+	OUT 83 Length: 0x01 "06"
+	OUT 83 Length: 0x01 "00"
+	IN  03 Length: 0x40 "00 FF FE FF FD FF 01 00 03 00 07 00 FE FF 08 00
+		03 00 00 00 FC FF 03 00 FF FF 00 00 01 00 03 00
+		FB FF F9 FF 01 00 FF FF FD FF 00 00 FE FF FA FF
+		FF FF FD FF 01 00 04 00 00 00 03 00 FB FF 01 00"
+
+ * Unknown commmand
+	IN  03 Length: 0x40 ...
+	OUT 83 Length: 0x01 "01"
+	IN  03 Length: 0x40 "01 42 FC 54 03 FF 01 00 03 00 07 00 FE FF 08 00
+		03 00 00 00 FC FF 03 00 FF FF 00 00 01 00 03 00
+		FB FF F9 FF 01 00 FF FF FD FF 00 00 FE FF FA FF
+		FF FF FD FF 01 00 04 00 00
+*/
+
+/* Following the messages that are sent prior and after setting the device
+ * no clue what they are good for - but they don't seem necessary
+static int snd_sl_phono_start(struct snd_kcontrol *kcontrol)
+{
+	unsigned char buffer[] = {0};
+	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+	return snd_usb_interrupt_trans(mixer->chip->dev,
+				usb_sndintpipe(mixer->chip->dev, 0x03),
+				buffer, 1, snd_sl_phono_receive);
+}
+
+static int snd_sl_phono_end(struct snd_kcontrol *kcontrol)
+{
+	unsigned char buffer[] = {6};
+	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+	return snd_usb_interrupt_trans(mixer->chip->dev,
+				usb_sndintpipe(mixer->chip->dev, 0x03),
+				buffer, 1, snd_sl_phono_receive);
+}
+*/
+
+static int snd_sl_phono_set(struct snd_kcontrol *kcontrol,
+	int value)
+{
+	int err;
+	const unsigned int bufferSize = 64;
+	unsigned char buffer[bufferSize];
+	unsigned char instructions[] = {7, 0};
+
+	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+
+/* One example of USB traffic by serato driver
+ * switching line to phono:
+
+	OUT 03 Length: 0x01 "00"
+
+	IN  83 Length: 0x40 ...
+	OUT 03 Length: 0x02 "07 00"
+	IN  83 Length: 0x40 "07 00 01 00 04 00 02 00 02 00 05 00 04 00 02 00
+		05 00 06 00 02 00 01 00 03 00 0E 00 05 00 0E 00
+		09 00 FF FF 02 00 02 00 05 00 03 00 FA FF 04 00
+		05 00 07 00 08 00 01 00 02 00 01 00 02 00 01 00"
+
+	IN  83 Length: 0x40 ...
+	OUT 03 Length: 0x01 "06"
+	IN  83 Length: 0x40 No answer!?
+
+ * switching phono to line:
+	OUT 03 Length: 0x01 "00"
+
+	IN  83 Length: 0x40 ...
+	OUT 03 Length: 0x02 "07 01"
+	IN  83 Length: 0x40 "07 FF F9 FF FB FF 01 00 FF FF FE FF F6 FF EF FF
+		F8 FF FD FF FB FF FC FF FA FF 00 00 FA FF F7 FF
+		F5 FF FB FF 01 00 F7 FF F7 FF FC FF F9 FF F9 FF
+		F7 FF F7 FF 00 00 F4 FF FB FF F6 FF F9 FF FA FF"
+
+	IN  83 Length: 0x40 ...
+	OUT 03 Length: 0x01 "06"
+	IN  83 Length: 0x40 No answer!?
+*/
+
+	if (value > 1)
+		return -EINVAL;
+
+	/* outcommented for now since it works without
+	 * and don't have a clue what it's good for
+	err = snd_sl_phono_start(kcontrol);
+	*/
+
+	err = snd_usb_interrupt_trans(mixer->chip->dev,
+				usb_rcvbulkpipe(mixer->chip->dev, 0x83),
+				buffer, bufferSize, snd_sl_phono_receive);
+
+	if (err < 0)
+		return err;
+
+	/* 07 00 = phone
+	   07 01 = line */
+	instructions[1] = !value;
+
+	err =  snd_usb_interrupt_trans(mixer->chip->dev,
+				usb_sndintpipe(mixer->chip->dev, 0x03),
+				instructions, 2, snd_sl_phono_receive);
+
+	if (err < 0)
+		return err;
+
+	err = snd_usb_interrupt_trans(mixer->chip->dev,
+				usb_rcvbulkpipe(mixer->chip->dev, 0x83),
+				buffer, bufferSize, snd_sl_phono_changed);
+
+	/* outcommented for now since it works without
+	 * and don't have a clue what it's good for
+	err = snd_sl_phono_end(kcontrol);
+	*/
+
+	if (err < 0)
+		return err;
+
+	kcontrol->private_value = value;
+	return 0;
+}
+
+static int snd_sl_phono_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	int err = 0;
+	int value = ucontrol->value.integer.value[0];
+
+	if (value == kcontrol->private_value)
+		return 0;
+
+	err = snd_sl_phono_set(kcontrol, value);
+
+	if (err < 0)
+		return err;
+
+	return 1;
+}
+
+static struct snd_kcontrol_new snd_sl_controls[] =
+{
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Phono Switch",
+		.info = snd_sl_phono_info,
+		.get = snd_sl_phono_get,
+		.put = snd_sl_phono_put,
+		.private_value = 1, /*switch is activated*/
+	}
+};
+
+/* gets called multiple times! */
+static int snd_sl_controls_create(struct usb_mixer_interface *mixer)
+{
+	int i, err;
+
+	for (i = 0; i < ARRAY_SIZE(snd_sl_controls); ++i) {
+		struct snd_kcontrol *kcontrol =
+			snd_ctl_new1(&snd_sl_controls[i], mixer);
+
+		/* Since we only need one control and the routine
+		 * is called multiple times we have to ignore all
+		 * attempts to attach controls multiple times*/
+		if (snd_ctl_find_id(mixer->chip->card, &kcontrol->id)) {
+			/* we found the control - it is already present
+			 * so just continue*/
+			snd_ctl_free_one(kcontrol);
+			continue;
+		}
+
+		/* add frees the control if on err < 0! */
+		err = snd_ctl_add(mixer->chip->card,
+			  kcontrol);
+		if (err < 0)
+			return err;
+
+		/* Make sure device is set to default */
+		err = snd_sl_phono_set(kcontrol, kcontrol->private_value);
+
+		if (err < 0) {
+			snd_ctl_free_one(kcontrol);
+			return err; /* the device screwed up */
+		}
+	}
+
+	return 0;
+}
+
 int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
 			 int ignore_error)
 {
@@ -2043,6 +2318,12 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
 	if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)
 		goto _error;
 
+	if (mixer->chip->usb_id == USB_ID(0x13e5, 0x001)) {
+		err = snd_sl_controls_create(mixer);
+		if (err < 0)
+			goto _error;
+	}
+
 	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
 	    mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) {
 		struct snd_info_entry *entry;
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux