All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: Driver for TerraTec DMX 6Fire USB
       [not found] <12d995c1fa0.477955495632923443.5387390398635058860@zoho.com>
@ 2011-01-20 16:54 ` Takashi Iwai
  2011-01-20 22:38   ` Torsten Schenk
  0 siblings, 1 reply; 22+ messages in thread
From: Takashi Iwai @ 2011-01-20 16:54 UTC (permalink / raw)
  To: torsten.schenk; +Cc: alsa-devel, clemens

At Tue, 18 Jan 2011 14:41:47 +0100,
torsten.schenk wrote:
> 
> Hello,
> 
> (to all those who already got this mail: sorry, I sent the attachment accidentally in html format so it was ignored by alsa-devel ML distributor)
> 
> i recently got a TerraTec DMX 6Fire USB. Since it's not supported by alsa, I decided to look into communications between the windows driver and the card. Here is the result.
> 
> What should be revised:
> - I was unsure about naming conventions, so please check the name of card/midi/pcm/module.
> - Also the device needs firmware to be able to run, so I included the firmware from the windows driver in the attachment. I read about that Linus Torvalds doesn't like .ihex-parsing in drivers, but I cannot convert the files easily into a binary format because the offsets are not contiguous. Of course there could be alternate ways to be thought about, which would imply that original files from TT are not supported since they are in ihex.
> - I didn't manage to create a configuration in /usr/share/alsa/cards.
> 
> What is working: Everything except SPDIF
> - Hardware Master volume
> - PCM 44-192kHz@24 bits, 6 channels out, 4 channels in (analog)
> - MIDI in/out
> - firmware loading for coldplugged devices
> - phono/line switching
> 
> If anything else comes to your attention, just let me know.

Sorry for the late reply.  It took some time until I have free slot.

First off, there are lots of coding-style issues to be fixed.
Try to run scripts/checkpatch.pl once with your patch.  Not all warnings
have to be fixed (e.g. 80-chars) but would be nice if fixed.

Here are some review comments through a very quirk glance:

> +static int __devinit probe(struct usb_interface *intf, const struct usb_device_id *usb_id)

Adding a short prefix (e.g. usb6fire_probe()) is better in general.
Otherwise the stack trace would be difficult to read.  Of course,
too long names are also annoying, so it's a matter of taste.

...
> +	chip = (struct sfire_chip*)card->private_data;

You can avoid cast here.

> +	chips[regidx] = chip;
> +	chip->dev = device;
> +	chip->regidx = regidx;
> +	chip->intf_count = 1;
> +	chip->card = card;
> +	chip->shutdown = FALSE;
> +	chip->midi = NULL;
> +	chip->comm = NULL;
> +	chip->control = NULL;
> +	chip->pcm = NULL;

NULLs are automatically filled, so these can be skipped.

> +	ret = snd_usb_6fire_comm_init(chip);
> +	if(ret < 0)
> +	{
> +		snd_card_free(card);
> +		return ret;
> +	}
> +
> +	ret = snd_usb_6fire_midi_init(chip);
> +	if(ret < 0)
> +	{
> +		snd_usb_6fire_comm_destroy(chip);
> +		snd_card_free(card);
> +		return ret;
> +	}
> +
> +	ret = snd_usb_6fire_pcm_init(chip);
> +	if(ret < 0)
> +	{
> +		snd_usb_6fire_midi_destroy(chip);
> +		snd_usb_6fire_comm_destroy(chip);
> +		snd_card_free(card);
> +		return ret;
> +	}
> +
> +	ret = snd_usb_6fire_control_init(chip);
> +	if(ret < 0)
> +	{
> +		snd_usb_6fire_pcm_destroy(chip);
> +		snd_usb_6fire_midi_destroy(chip);
> +		snd_usb_6fire_comm_destroy(chip);
> +		snd_card_free(card);
> +		return ret;
> +	}
> +
> +	ret = snd_card_register(card);
> +	if(ret < 0)
> +	{
> +		snd_usb_6fire_pcm_destroy(chip);
> +		snd_usb_6fire_midi_destroy(chip);
> +		snd_usb_6fire_comm_destroy(chip);
> +		snd_usb_6fire_control_destroy(chip);
> +		snd_card_free(card);

A general way for error-handling is either using goto or using a
common destructor.  In either way, you can call the *_free or *_destroy
with the non-NULL check of each instance.  It's a cleaner in general.

> +static void disconnect(struct usb_interface *intf)
> +{
> +	struct sfire_chip *chip;
> +	struct snd_card *card;
> +	
> +	chip = usb_get_intfdata(intf);
> +	if(chip) //if !chip, fw upload has been performed so that we don't have a chip.
> +	{
> +		card = chip->card;
> +		chip->intf_count--;
> +		if (chip->intf_count == 0)
> +		{
> +			chip->shutdown = TRUE;
> +			snd_card_disconnect(card);
> +			snd_usb_6fire_comm_destroy(chip);
> +			snd_usb_6fire_control_destroy(chip);
> +			snd_usb_6fire_pcm_destroy(chip);
> +			snd_usb_6fire_midi_destroy(chip);
> +			snd_card_free(card);
> +			usb_set_intfdata(intf, NULL);

The same destructor as in probe can be used here.

> +static struct usb_device_id device_table[] =
> +{
> +	{
> +		.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
> +		.idVendor = 0x0ccd,
> +		.idProduct = 0x0080
> +	},
> +	{ }
> +};

Usually MODULE_DEVICE_TABLE() follows just after the definition.

> diff -Nur a/sound/usb/6fire/chip.h b/sound/usb/6fire/chip.h
> --- a/sound/usb/6fire/chip.h	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/chip.h	2011-01-18 13:58:06.000000000 +0100
> @@ -0,0 +1,30 @@
> +/*
> + * Linux driver for TerraTec DMX 6Fire USB
> + *
> + * Author: Torsten Schenk
> + * Created: Jan 01, 2011
> + * Copyright:	(C) Torsten Schenk
> + *
> + * 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
> + * (at your option) any later version.
> + */
> +#pragma once

Don't use prgram.
Also, add #ifdef xxx for protecting the double inclusion.

> +#include "common.h"
> +
> +struct sfire_chip
> +{
> +	struct usb_device *dev;
> +	struct snd_card *card;
> +	int intf_count; //number of registered interfaces
> +	int regidx; //index in module parameter arrays
> +	BOOL shutdown;

Don't use own bool type.  Use the generic "bool" type, and use
true/false instead of TRUE/FALSE (unless the size really matters).

> diff -Nur a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
> --- a/sound/usb/6fire/comm.c	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/comm.c	2011-01-18 13:58:21.000000000 +0100
...
> +static int write_02(struct comm_runtime *rt, __u8 reg, __u16 value)

Use u8 and u16.

> diff -Nur a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h
> --- a/sound/usb/6fire/comm.h	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/comm.h	2011-01-18 13:58:29.000000000 +0100
> @@ -0,0 +1,42 @@
> +/*
> + * Linux driver for TerraTec DMX 6Fire USB
> + *
> + * Author: Torsten Schenk
> + * Created: Jan 01, 2011
> + * Copyright:	(C) Torsten Schenk
> + *
> + * 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
> + * (at your option) any later version.
> + */
> +
> +#pragma once

Ditto.  No pragma and add ifdef.

> diff -Nur a/sound/usb/6fire/common.h b/sound/usb/6fire/common.h
> --- a/sound/usb/6fire/common.h	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/common.h	2011-01-18 13:58:38.000000000 +0100
> +#pragma once
> +
> +#include <linux/slab.h>
> +#include <linux/usb.h>
> +#include <sound/core.h>
> +
> +#define BOOL char
> +#define TRUE 1
> +#define FALSE 0

Don't use these.

> +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
> +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))

Use standard min() / max() macros.

> +#define ERR KERN_ERR "6fire: "
> +#define WARNING KERN_WARNING "6fire: "

Hmm... These are also better to be avoided.  At most, define
"6fire: " as PREFIX or PFX or whatever.  But KERN_ERR should be put
plainly.

> diff -Nur a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
> --- a/sound/usb/6fire/control.c	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/control.c	2011-01-18 13:58:57.000000000 +0100
> diff -Nur a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
> --- a/sound/usb/6fire/firmware.c	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/firmware.c	2011-01-18 13:57:15.000000000 +0100
...
> +static inline int fpga_write(struct usb_device *device, char *data, int len)

Avoid inline unless you really need it.
Also add MODULE_FIRMWARE() definitions in this file.

> diff -Nur a/sound/usb/6fire/Makefile b/sound/usb/6fire/Makefile
> --- a/sound/usb/6fire/Makefile	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/Makefile	2011-01-16 23:14:22.000000000 +0100
> @@ -0,0 +1,13 @@
> +obj-m += snd-usb-6fire.o
> +snd-usb-6fire-objs += chip.o comm.o midi.o control.o firmware.o pcm.o
> +
> +all:
> +	make CONFIG_DEBUG_SECTION_MISMATCH=y -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
> +
> +clean:
> +	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
> +
> +install:
> +	mkdir -p /lib/modules/$(shell uname -r)/extras
> +	cp snd-usb-6fire.ko /lib/modules/$(shell uname -r)/extras

Remove all, clean, install things.

> diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
> --- a/sound/usb/6fire/pcm.c	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/pcm.c	2011-01-18 13:59:57.000000000 +0100
> diff -Nur a/sound/usb/Kconfig b/sound/usb/Kconfig
> --- a/sound/usb/Kconfig	2011-01-16 23:20:41.000000000 +0100
> +++ b/sound/usb/Kconfig	2011-01-16 23:14:22.000000000 +0100
> @@ -32,6 +32,17 @@
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called snd-ua101.
 
> +config SND_USB_6FIRE
> +	tristate "TerraTec DMX 6Fire USB"
> +	depends on X86
> +	select SND_HWDEP

Do you really need hwdep?
Rather select FW_LOADER, if any.

> +	select SND_PCM

Missing SND_RAWMIDI dependency.


> @@ -65,7 +76,6 @@
>  	    * Native Instruments Guitar Rig Session I/O
>  	    * Native Instruments Guitar Rig mobile
>  	    * Native Instruments Traktor Kontrol X1
> -	    * Native Instruments Traktor Kontrol S4
 
>  	   To compile this driver as a module, choose M here: the module
>  	   will be called snd-usb-caiaq.
> @@ -83,7 +93,6 @@
>  	   * Native Instruments Kore Controller
>  	   * Native Instruments Kore Controller 2
>  	   * Native Instruments Audio Kontrol 1
> -	   * Native Instruments Traktor Kontrol S4
 
Don't bother others ;)


thanks,

Takashi

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Driver for TerraTec DMX 6Fire USB
  2011-01-20 16:54 ` Driver for TerraTec DMX 6Fire USB Takashi Iwai
@ 2011-01-20 22:38   ` Torsten Schenk
  2011-01-21  8:57     ` Takashi Iwai
  0 siblings, 1 reply; 22+ messages in thread
From: Torsten Schenk @ 2011-01-20 22:38 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

[-- Attachment #1: Type: text/plain, Size: 3094 bytes --]

Hello,

Thanks very much for the review. I corrected the issues you wrote about (except the last one, see below). checkpatch.pl reports now 0 errors and warnings.

Another thing about the driver's features:
I'm currently in contact with a guy that also owns a TT DMX6FireUSB. He says, firmware is not loading for him. I'm trying to figure out how to make
it work, but I already know, that my driver cannot provide fw uploading for every device out there by now. I think it's just a matter of removing some checks, but I want to make as sure as I can before I just do so.

If the device was previously used in windows and not unplugged from power, it will work also with no firmware upload.

>First off, there are lots of coding-style issues to be fixed. 
>Try to run scripts/checkpatch.pl once with your patch. Not all warnings 
>have to be fixed (e.g. 80-chars) but would be nice if fixed.
I though so. checkpatch.pl is a useful script, good to know it exists.

>Adding a short prefix (e.g. usb6fire_probe()) is better in general. 
>Otherwise the stack trace would be difficult to read. Of course, 
>too long names are also annoying, so it's a matter of taste. 
How is it supposed to be? I reviewed my code and added a prefix to every function. Hopefully
it didn't get too long now... Some, especially functions with not much content, seem to have a too long name by now for my flavour. 

>NULLs are automatically filled, so these can be skipped. 
Which NULLs are automatically filled? Just the area create by snd_card_create or
every area allocated via kmalloc? If last is true, I will have to remove some more NULLs.

>Don't use own bool type. Use the generic "bool" type, and use 
>true/false instead of TRUE/FALSE (unless the size really matters). 
>Use standard min() / max() macros. 
>Use u8 and u16. 
Didn't know these exists...
When I used C once, 'bool' and also 'min'/'max' weren't available.

>Remove all, clean, install things. 
Just forgot ;)

>Do you really need hwdep? 
>Rather select FW_LOADER, if any. 
> 
>> +    select SND_PCM 
Thanks, just copied this from another definition without exactly knowing what it does...
> 
>Missing SND_RAWMIDI dependency. 
Realized that after posting.

> 
> 
>> @@ -65,7 +76,6 @@ 
>>      * Native Instruments Guitar Rig Session I/O 
>>      * Native Instruments Guitar Rig mobile 
>>      * Native Instruments Traktor Kontrol X1 
>> -     * Native Instruments Traktor Kontrol S4 
> 
>>      To compile this driver as a module, choose M here: the module 
>>      will be called snd-usb-caiaq. 
>> @@ -83,7 +93,6 @@ 
>>      * Native Instruments Kore Controller 
>>      * Native Instruments Kore Controller 2 
>>      * Native Instruments Audio Kontrol 1 
>> -     * Native Instruments Traktor Kontrol S4 
> 
>Don't bother others ;) 
I'd love not to ;) But how can I remove it? It's automatically generated by diff. Perhaps wrong arguments? Mine are -Nur
Or should I simply remove these lines with a text editor?

Greetings,
Torsten

[-- Attachment #2: usb6fire.tar.bz2 --]
[-- Type: application/octet-stream, Size: 13210 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Driver for TerraTec DMX 6Fire USB
  2011-01-20 22:38   ` Torsten Schenk
@ 2011-01-21  8:57     ` Takashi Iwai
  2011-01-21 11:48       ` Torsten Schenk
  0 siblings, 1 reply; 22+ messages in thread
From: Takashi Iwai @ 2011-01-21  8:57 UTC (permalink / raw)
  To: Torsten Schenk; +Cc: alsa-devel, clemens

At Thu, 20 Jan 2011 23:38:50 +0100,
Torsten Schenk wrote:
> 
> Hello,
> 
> Thanks very much for the review. I corrected the issues you wrote about (except the last one, see below). checkpatch.pl reports now 0 errors and warnings.
> 
> Another thing about the driver's features:
> I'm currently in contact with a guy that also owns a TT DMX6FireUSB. He says, firmware is not loading for him. I'm trying to figure out how to make
> it work, but I already know, that my driver cannot provide fw uploading for every device out there by now. I think it's just a matter of removing some checks, but I want to make as sure as I can before I just do so.
> 
> If the device was previously used in windows and not unplugged from power, it will work also with no firmware upload.

Could you put such information in either git changelog, some
document or in a comment in the source code?


> >First off, there are lots of coding-style issues to be fixed. 
> >Try to run scripts/checkpatch.pl once with your patch. Not all warnings 
> >have to be fixed (e.g. 80-chars) but would be nice if fixed.
> I though so. checkpatch.pl is a useful script, good to know it exists.
> 
> >Adding a short prefix (e.g. usb6fire_probe()) is better in general. 
> >Otherwise the stack trace would be difficult to read. Of course, 
> >too long names are also annoying, so it's a matter of taste. 
> How is it supposed to be? I reviewed my code and added a prefix to every function. Hopefully
> it didn't get too long now... Some, especially functions with not much content, seem to have a too long name by now for my flavour. 
> 
> >NULLs are automatically filled, so these can be skipped. 
> Which NULLs are automatically filled? Just the area create by snd_card_create or
> every area allocated via kmalloc? If last is true, I will have to remove some more NULLs.

Not with kmalloc.  There is kzalloc or kcalloc for such purpose.
The space allocated via snd_card_new() is zero-cleared.


> >Don't use own bool type. Use the generic "bool" type, and use 
> >true/false instead of TRUE/FALSE (unless the size really matters). 
> >Use standard min() / max() macros. 
> >Use u8 and u16. 
> Didn't know these exists...
> When I used C once, 'bool' and also 'min'/'max' weren't available.
> 
> >Remove all, clean, install things. 
> Just forgot ;)
> 
> >Do you really need hwdep? 
> >Rather select FW_LOADER, if any. 
> > 
> >> +    select SND_PCM 
> Thanks, just copied this from another definition without exactly knowing what it does...
> > 
> >Missing SND_RAWMIDI dependency. 
> Realized that after posting.
> 
> > 
> > 
> >> @@ -65,7 +76,6 @@ 
> >>      * Native Instruments Guitar Rig Session I/O 
> >>      * Native Instruments Guitar Rig mobile 
> >>      * Native Instruments Traktor Kontrol X1 
> >> -     * Native Instruments Traktor Kontrol S4 
> > 
> >>      To compile this driver as a module, choose M here: the module 
> >>      will be called snd-usb-caiaq. 
> >> @@ -83,7 +93,6 @@ 
> >>      * Native Instruments Kore Controller 
> >>      * Native Instruments Kore Controller 2 
> >>      * Native Instruments Audio Kontrol 1 
> >> -     * Native Instruments Traktor Kontrol S4 
> > 
> >Don't bother others ;) 
> I'd love not to ;) But how can I remove it? It's automatically generated by diff. Perhaps wrong arguments? Mine are -Nur

It means that your driver code tree isn't sync'ed with the latest
tree.  Just rebase your tree to the latest one.  Or...

> Or should I simply remove these lines with a text editor?

This is an easy alternative.

Below is a few more review comments I found in your new patch.
Could you fix and resend?


thanks,

Takashi

> diff -Nur a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
> --- a/sound/usb/6fire/chip.c	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/chip.c	2011-01-20 22:56:37.000000000 +0100
> +static int __devinit usb6fire_chip_probe(struct usb_interface *intf,
> +		const struct usb_device_id *usb_id)
..
> +	/* look if we already serve this card and return if so */
> +	mutex_lock(&register_mutex);
> +	for (i = 0; i < SNDRV_CARDS; i++)
> +		if (devices[i] == device) {
> +			if (chips[i])
> +				chips[i]->intf_count++;
> +			usb_set_intfdata(intf, chips[i]);
> +			mutex_unlock(&register_mutex);
> +			return 0;
> +		} else if (regidx < 0)
> +			regidx = i;
> +		if (regidx < 0) {

The for block should be a block with {...}, as it's no one-line if
statement.

> +static void usb6fire_chip_disconnect(struct usb_interface *intf)
> +{
> +	struct sfire_chip *chip;
> +	struct snd_card *card;
> +
> +	chip = usb_get_intfdata(intf);
> +	if (chip) { /* if !chip, fw upload has been performed */
> +		card = chip->card;
> +		chip->intf_count--;
> +		if (!chip->intf_count) {
> +			chip->shutdown = true;
> +			snd_card_disconnect(card);
> +			usb6fire_chip_destroy(chip);
> +			usb_set_intfdata(intf, NULL);
> +		}
> +	}

chips[] and devices[] aren't cleared at disconnect?

> diff -Nur a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
> --- a/sound/usb/6fire/control.c	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/control.c	2011-01-20 23:03:32.000000000 +0100
> @@ -0,0 +1,279 @@
> +/*
> + * Linux driver for TerraTec DMX 6Fire USB
> + *
> + * Mixer control
> + *
> + * Author: Torsten Schenk
> + * Created: Jan 01, 2011
> + * Copyright:	(C) Torsten Schenk
> + *
> + * 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
> + * (at your option) any later version.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <sound/control.h>
> +
> +#include "control.h"
> +#include "comm.h"
> +#include "chip.h"
> +
> +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,

Begin the data in the next line.  And use one-tab indent.

> +		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.
> + */
> +static const struct {
> +	u8 type;
> +	u8 reg;
> +	u8 value;
> +} init_data[] = {

Ditto.

> +			{ 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 },
> +			{ 0x22, 0x01, 0x01 }, { 0x20, 0x01, 0x08 },
> +			{ 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 },
> +			{ 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, 0x23, 0x00 }, { 0x12, 0x06, 0x02 },
> +			{ 0x12, 0x03, 0x00 }, { 0x12, 0x02, 0x00 },
> +			{ 0x22, 0x03, 0x01 },
> +			{ 0 } /* TERMINATING ENTRY */
> +};
> +
> diff -Nur a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
> --- a/sound/usb/6fire/firmware.c	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/firmware.c	2011-01-20 23:09:59.000000000 +0100
> +static const u8 BIT_REVERSE_TABLE[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0,
> +		0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,

Ditto.

> +		0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98,
> +		0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
> +		0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4,
> +		0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
> +		0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82,
> +		0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2,
> +		0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa,
> +		0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
> +		0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96,
> +		0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce,
> +		0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe,
> +		0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
> +		0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89,
> +		0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
> +		0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5,
> +		0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
> +		0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d,
> +		0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3,
> +		0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3,
> +		0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
> +		0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87,
> +		0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7,
> +		0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf,
> +		0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff };
> +
> +/*
> + * wMaxPacketSize of pcm endpoints.
> + * Order: ALT1EP2 ALT1EP6 ALT2EP2 ALT2EP6 ALT3EP2 ALT3EP6
> + * keep synced with RATES_IN_PACKET_SIZE and RATES_OUT_PACKET_SIZE in pcm.c
> + *
> + * CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init
> + */
> +static const u16 EP_W_MAX_PACKET_SIZE[] = { 228, 228, 420, 420, 404, 604 };
> +
> +struct ihex_record {
> +	u16 address;
> +	u8 len;
> +	u8 data[256];
> +	char error; /* true if an error occured parsing this record */
> +
> +	u8 max_len; /* maximum record length in whole ihex */
> +
> +	/* private */
> +	const char *txt_data;
> +	unsigned int txt_length;
> +	unsigned int txt_offset; /* current position in txt_data */
> +};
> +
> +static u8 usb6fire_fw_ihex_nibble(const u8 n)
> +{
> +	if (n >= '0' && n <= '9')
> +		return n - '0';
> +	else if (n >= 'A' && n <= 'F')
> +		return n - ('A' - 10);
> +	else if (n >= 'a' && n <= 'f')
> +		return n - ('a' - 10);
> +	return 0;
> +}
> +static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc)
> +{
> +	u8 val = (usb6fire_fw_ihex_nibble(data[0]) << 4) |
> +			usb6fire_fw_ihex_nibble(data[1]);
> +	*crc += val;
> +	return val;
> +}
> +
> +/*
> + * returns true if record is available, false otherwise.
> + * iff an error occured, false will be returned and record->error will be true.
> + */
> +static bool usb6fire_fw_ihex_next_record(struct ihex_record *record)
> +{
> +	u8 crc = 0;
> +	u8 type;
> +	int i;
> +
> +	record->error = false;
> +
> +	/* find begin of record (marked by a colon) */
> +	while (record->txt_offset < record->txt_length
> +			&& record->txt_data[record->txt_offset] != ':')
> +		record->txt_offset++;
> +	if (record->txt_offset == record->txt_length)
> +		return false;
> +
> +	/* number of characters needed for len, addr and type entries */
> +	record->txt_offset++;
> +	if (record->txt_offset + 8 > record->txt_length) {
> +		record->error = true;
> +		return false;
> +	}
> +
> +	record->len = usb6fire_fw_ihex_hex(record->txt_data +
> +			record->txt_offset, &crc);
> +	record->txt_offset += 2;
> +	record->address = usb6fire_fw_ihex_hex(record->txt_data +
> +			record->txt_offset, &crc) << 8;
> +	record->txt_offset += 2;
> +	record->address |= usb6fire_fw_ihex_hex(record->txt_data +
> +			record->txt_offset, &crc);
> +	record->txt_offset += 2;
> +	type = usb6fire_fw_ihex_hex(record->txt_data +
> +			record->txt_offset, &crc);
> +	record->txt_offset += 2;
> +
> +	/* number of characters needed for data and crc entries */
> +	if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) {
> +		record->error = true;
> +		return false;
> +	}
> +	for (i = 0; i < record->len; i++) {
> +		record->data[i] = usb6fire_fw_ihex_hex(record->txt_data
> +				+ record->txt_offset, &crc);
> +		record->txt_offset += 2;
> +	}
> +	usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc);
> +	if (crc) {
> +		record->error = true;
> +		return false;
> +	}
> +
> +	if (type == 1 || !record->len) /* eof */
> +		return false;
> +	else if (type == 0)
> +		return true;
> +	else {
> +		record->error = true;
> +		return false;
> +	}
> +}
> +
> +static int usb6fire_fw_ihex_init(const struct firmware *fw,
> +		struct ihex_record *record)
> +{
> +	record->txt_data = fw->data;
> +	record->txt_length = fw->size;
> +	record->txt_offset = 0;
> +	record->max_len = 0;
> +	/* read all records, if loop ends, record->error indicates,
> +	 * whether ihex is valid. */
> +	while (usb6fire_fw_ihex_next_record(record))
> +		record->max_len = max(record->len, record->max_len);
> +	if (record->error)
> +		return -EINVAL;
> +	record->txt_offset = 0;
> +	return 0;
> +}

I found that the recent kernel has linux/ihex.h helper functions.
They might help for simplifying the code.  But, this can be done later
as a a clean-up.

> diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
> --- a/sound/usb/6fire/pcm.c	1970-01-01 01:00:00.000000000 +0100
> +++ b/sound/usb/6fire/pcm.c	2011-01-20 23:07:24.000000000 +0100
...
> +/* keep next two synced with
> + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
> +static const int RATES_IN_PACKET_SIZE[] = { 228, 228, 420, 420, 404, 404 };
> +static const int RATES_OUT_PACKET_SIZE[] = { 228, 228, 420, 420, 604, 604 };
> +static const int RATES[] = { 44100, 48000, 88200, 96000, 176400, 192000 };

Any reason to use capital letters for these?
Because they are const?

> +static const int RATES_ALSAID[] = { SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,

Begin the data in the open line, and use a proper indent.

> +		SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
> +		SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
> +static const int RATES_ALTSETTING[] = { 1, 1, 2, 2, 3, 3 };
> +
> +/* values to write to soundcard register for all samplerates */
> +static const __u16 RATES_6FIRE_VL[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
> +static const __u16 RATES_6FIRE_VH[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};

Use u16.

> diff -Nur a/sound/usb/Kconfig b/sound/usb/Kconfig
> --- a/sound/usb/Kconfig	2011-01-16 23:20:41.000000000 +0100
> +++ b/sound/usb/Kconfig	2011-01-20 23:25:34.000000000 +0100
> @@ -32,6 +32,19 @@
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called snd-ua101.
 
> +config SND_USB_6FIRE
> +	tristate "TerraTec DMX 6Fire USB"
> +	depends on X86

Why x86-dependent?


thanks,

Takashi
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Driver for TerraTec DMX 6Fire USB
  2011-01-21  8:57     ` Takashi Iwai
@ 2011-01-21 11:48       ` Torsten Schenk
  2011-01-22 16:35         ` Takashi Iwai
  2011-03-31 19:25         ` TerraTec DMX 6Fire USB updates Torsten Schenk
  0 siblings, 2 replies; 22+ messages in thread
From: Torsten Schenk @ 2011-01-21 11:48 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

[-- Attachment #1: Type: text/plain, Size: 1563 bytes --]

>It means that your driver code tree isn't sync'ed with the latest 
>tree. Just rebase your tree to the latest one. Or... 
The trick is, I have a kernel tree that only contains this Kconfig. So these two should be the same, because I copied them.
No matter, I edited the patch manually and hope it will perform as it should.

>I found that the recent kernel has linux/ihex.h helper functions. 
>They might help for simplifying the code. But, this can be done later 
>as a a clean-up. 
Yes, I also discovered this helper function, but it supports only some kind of binary ihex format. It did not accept
the text .ihx files.

> 
>> diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c 
>> --- a/sound/usb/6fire/pcm.c    1970-01-01 01:00:00.000000000 +0100 
>> +++ b/sound/usb/6fire/pcm.c    2011-01-20 23:07:24.000000000 +0100 
>... 
>> +/* keep next two synced with 
>> + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */ 
>> +static const int RATES_IN_PACKET_SIZE[] = { 228, 228, 420, 420, 404, 404 }; 
>> +static const int RATES_OUT_PACKET_SIZE[] = { 228, 228, 420, 420, 604, 604 }; 
>> +static const int RATES[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; 
> 
>Any reason to use capital letters for these? 
>Because they are const? 
That was exactly the idea.

>Why x86-dependent? 
I thought so because of the firmware stuff. If bit- or byte-order are changed, the firmware uploading might not work. If I figured out the #ifdef stuff for bit and byte order, I will remove this dependency.

Thanks,
Torsten

[-- Attachment #2: usb6fire.tar.bz2 --]
[-- Type: application/octet-stream, Size: 13280 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Driver for TerraTec DMX 6Fire USB
  2011-01-21 11:48       ` Torsten Schenk
@ 2011-01-22 16:35         ` Takashi Iwai
  2011-01-24 12:10           ` Torsten Schenk
  2011-03-31 19:25         ` TerraTec DMX 6Fire USB updates Torsten Schenk
  1 sibling, 1 reply; 22+ messages in thread
From: Takashi Iwai @ 2011-01-22 16:35 UTC (permalink / raw)
  To: Torsten Schenk; +Cc: alsa-devel, clemens

At Fri, 21 Jan 2011 12:48:52 +0100,
Torsten Schenk wrote:
> 
> >I found that the recent kernel has linux/ihex.h helper functions. 
> >They might help for simplifying the code. But, this can be done later 
> >as a a clean-up. 
> Yes, I also discovered this helper function, but it supports only some kind of binary ihex format. It did not accept
> the text .ihx files.

OK.

> >> diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c 
> >> --- a/sound/usb/6fire/pcm.c    1970-01-01 01:00:00.000000000 +0100 
> >> +++ b/sound/usb/6fire/pcm.c    2011-01-20 23:07:24.000000000 +0100 
> >... 
> >> +/* keep next two synced with 
> >> + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */ 
> >> +static const int RATES_IN_PACKET_SIZE[] = { 228, 228, 420, 420, 404, 404 }; 
> >> +static const int RATES_OUT_PACKET_SIZE[] = { 228, 228, 420, 420, 604, 604 }; 
> >> +static const int RATES[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; 
> > 
> >Any reason to use capital letters for these? 
> >Because they are const? 
> That was exactly the idea.

Hm, but it's not so common.  Not too annoying as well, though.

> >Why x86-dependent? 
> I thought so because of the firmware stuff. If bit- or byte-order are changed, the firmware uploading might not work. If I figured out the #ifdef stuff for bit and byte order, I will remove this dependency.

But you are decoding in bytes, not in words or so.  Thus the CPU
byte-order doesn't matter.


thanks,

Takashi
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Driver for TerraTec DMX 6Fire USB
  2011-01-22 16:35         ` Takashi Iwai
@ 2011-01-24 12:10           ` Torsten Schenk
  2011-01-25 10:25             ` Takashi Iwai
  0 siblings, 1 reply; 22+ messages in thread
From: Torsten Schenk @ 2011-01-24 12:10 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

[-- Attachment #1: Type: text/plain, Size: 1637 bytes --]

Hello,

I had to review the code since an error came up: when sound was playing and I disconnected the device, the whole system crashed. This bug is now solved (pcm.c: check if a isoc-packet has invalid status on retire, if so, abort streaming).

>> >> diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c 
>> >> --- a/sound/usb/6fire/pcm.c    1970-01-01 01:00:00.000000000 +0100 
>> >> +++ b/sound/usb/6fire/pcm.c    2011-01-20 23:07:24.000000000 +0100 
>> >... 
>> >> +/* keep next two synced with 
>> >> + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */ 
>> >> +static const int RATES_IN_PACKET_SIZE[] = { 228, 228, 420, 420, 404, 404 }; 
>> >> +static const int RATES_OUT_PACKET_SIZE[] = { 228, 228, 420, 420, 604, 604 }; 
>> >> +static const int RATES[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; 
>> > 
>> >Any reason to use capital letters for these? 
>> >Because they are const? 
>> That was exactly the idea. 
> 
>Hm, but it's not so common. Not too annoying as well, though. 
Ok, I thought it would be that way... No matter, I changed it to small letters.

>> >Why x86-dependent? 
>> I thought so because of the firmware stuff. If bit- or byte-order are changed, the firmware uploading might not work. If I figured out the #ifdef stuff for bit and byte order, I will remove this dependency. 
> 
>But you are decoding in bytes, not in words or so. Thus the CPU 
>byte-order doesn't matter. 
I reviewed the code and found exactly one endian-dependend thing: a const array I defined with type u16. I changed that to u8 and removed the x86 dependency.

Greetings,
Torsten

[-- Attachment #2: usb6fire.tar.bz2 --]
[-- Type: application/octet-stream, Size: 13105 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Driver for TerraTec DMX 6Fire USB
  2011-01-24 12:10           ` Torsten Schenk
@ 2011-01-25 10:25             ` Takashi Iwai
  2011-01-25 14:12               ` Torsten Schenk
  0 siblings, 1 reply; 22+ messages in thread
From: Takashi Iwai @ 2011-01-25 10:25 UTC (permalink / raw)
  To: Torsten Schenk; +Cc: alsa-devel, clemens

At Mon, 24 Jan 2011 13:10:58 +0100,
Torsten Schenk wrote:
> 
> Hello,
> 
> I had to review the code since an error came up: when sound was playing and I disconnected the device, the whole system crashed. This bug is now solved (pcm.c: check if a isoc-packet has invalid status on retire, if so, abort streaming).
> 
> >> >> diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c 
> >> >> --- a/sound/usb/6fire/pcm.c    1970-01-01 01:00:00.000000000 +0100 
> >> >> +++ b/sound/usb/6fire/pcm.c    2011-01-20 23:07:24.000000000 +0100 
> >> >... 
> >> >> +/* keep next two synced with 
> >> >> + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */ 
> >> >> +static const int RATES_IN_PACKET_SIZE[] = { 228, 228, 420, 420, 404, 404 }; 
> >> >> +static const int RATES_OUT_PACKET_SIZE[] = { 228, 228, 420, 420, 604, 604 }; 
> >> >> +static const int RATES[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; 
> >> > 
> >> >Any reason to use capital letters for these? 
> >> >Because they are const? 
> >> That was exactly the idea. 
> > 
> >Hm, but it's not so common. Not too annoying as well, though. 
> Ok, I thought it would be that way... No matter, I changed it to small letters.
> 
> >> >Why x86-dependent? 
> >> I thought so because of the firmware stuff. If bit- or byte-order are changed, the firmware uploading might not work. If I figured out the #ifdef stuff for bit and byte order, I will remove this dependency. 
> > 
> >But you are decoding in bytes, not in words or so. Thus the CPU 
> >byte-order doesn't matter. 
> I reviewed the code and found exactly one endian-dependend thing: a const array I defined with type u16. I changed that to u8 and removed the x86 dependency.

Thanks.  I committed your patch yesterday to sound git tree.

For further works, please base on the latest sound git tree.


Takashi
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Driver for TerraTec DMX 6Fire USB
  2011-01-25 10:25             ` Takashi Iwai
@ 2011-01-25 14:12               ` Torsten Schenk
  0 siblings, 0 replies; 22+ messages in thread
From: Torsten Schenk @ 2011-01-25 14:12 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

>Thanks. I committed your patch yesterday to sound git tree. 
> 
>For further works, please base on the latest sound git tree. 
Ok. Thanks very much.

Greetings, Torsten

^ permalink raw reply	[flat|nested] 22+ messages in thread

* TerraTec DMX 6Fire USB updates
  2011-01-21 11:48       ` Torsten Schenk
  2011-01-22 16:35         ` Takashi Iwai
@ 2011-03-31 19:25         ` Torsten Schenk
  2011-04-01 12:52           ` Takashi Iwai
  1 sibling, 1 reply; 22+ messages in thread
From: Torsten Schenk @ 2011-03-31 19:25 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

[-- Attachment #1: Type: text/plain, Size: 190 bytes --]

Hello everyone,

The driver I wrote for the 6fire usb is now in use by some people so that I got feedback. This enabled me to improve and bugfix some things. Here the patch.

Greets,
Torsten

[-- Attachment #2: usb6fire.patch --]
[-- Type: application/octet-stream, Size: 18500 bytes --]

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

diff -Nur a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
--- a/sound/usb/6fire/chip.c	2011-03-31 21:14:19.576972975 +0200
+++ b/sound/usb/6fire/chip.c	2011-03-31 21:07:57.019973211 +0200
@@ -5,7 +5,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.4
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,7 @@
 #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, version 0.3.4");
 MODULE_LICENSE("GPL v2");
 MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
 
diff -Nur a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
--- a/sound/usb/6fire/control.c	2011-03-31 21:14:19.575972963 +0200
+++ b/sound/usb/6fire/control.c	2011-03-31 21:07:57.018973241 +0200
@@ -5,7 +5,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.4
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -65,6 +65,15 @@
 	{ 0 } /* TERMINATING ENTRY */
 };
 
+static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
+/* values to write to soundcard register for all samplerates */
+static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
+static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
+
+enum {
+	DIGITAL_THRU_ONLY_SAMPLERATE = 3
+};
+
 static void usb6fire_control_master_vol_update(struct control_runtime *rt)
 {
 	struct comm_runtime *comm_rt = rt->chip->comm;
@@ -95,6 +104,67 @@
 	}
 }
 
+static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
+{
+	int ret;
+	struct usb_device *device = rt->chip->dev;
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (rate < 0 || rate >= CONTROL_N_RATES)
+		return -EINVAL;
+
+	ret = usb_set_interface(device, 1, rates_altsetting[rate]);
+	if (ret < 0)
+		return ret;
+
+	/* set soundcard clock */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
+			rates_6fire_vh[rate]);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int usb6fire_control_set_channels(
+	struct control_runtime *rt, int n_analog_out,
+	int n_analog_in, bool spdif_out, bool spdif_in)
+{
+	int ret;
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	/* enable analog inputs and outputs
+	 * (one bit per stereo-channel) */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
+			(1 << (n_analog_out / 2)) - 1,
+			(1 << (n_analog_in / 2)) - 1);
+	if (ret < 0)
+		return ret;
+
+	/* disable digital inputs and outputs */
+	/* TODO: use spdif_x to enable/disable digital channels */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int usb6fire_control_streaming_update(struct control_runtime *rt)
+{
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (comm_rt) {
+		if (!rt->usb_streaming && rt->digital_thru_switch)
+			usb6fire_control_set_rate(rt,
+				DIGITAL_THRU_ONLY_SAMPLERATE);
+		return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
+			(rt->usb_streaming ? 0x01 : 0x00) |
+			(rt->digital_thru_switch ? 0x08 : 0x00));
+	}
+	return -EINVAL;
+}
+
 static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_info *uinfo)
 {
@@ -195,6 +265,38 @@
 	return 0;
 }
 
+static int usb6fire_control_digital_thru_info(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+
+	if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
+		rt->digital_thru_switch = ucontrol->value.integer.value[0];
+		usb6fire_control_streaming_update(rt);
+		changed = 1;
+	}
+	return changed;
+}
+
+static int usb6fire_control_digital_thru_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->digital_thru_switch;
+	return 0;
+}
+
 static struct __devinitdata snd_kcontrol_new elements[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -223,6 +325,15 @@
 		.get = usb6fire_control_opt_coax_get,
 		.put = usb6fire_control_opt_coax_put
 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Digital Thru Playback Route",
+		.index = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = usb6fire_control_digital_thru_info,
+		.get = usb6fire_control_digital_thru_get,
+		.put = usb6fire_control_digital_thru_put
+	},
 	{}
 };
 
@@ -238,6 +349,9 @@
 		return -ENOMEM;
 
 	rt->chip = chip;
+	rt->update_streaming = usb6fire_control_streaming_update;
+	rt->set_rate = usb6fire_control_set_rate;
+	rt->set_channels = usb6fire_control_set_channels;
 
 	i = 0;
 	while (init_data[i].type) {
@@ -249,6 +363,7 @@
 	usb6fire_control_opt_coax_update(rt);
 	usb6fire_control_line_phono_update(rt);
 	usb6fire_control_master_vol_update(rt);
+	usb6fire_control_streaming_update(rt);
 
 	i = 0;
 	while (elements[i].name) {
diff -Nur a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h
--- a/sound/usb/6fire/control.h	2011-03-31 21:14:19.575972963 +0200
+++ b/sound/usb/6fire/control.h	2011-03-31 21:07:57.018973241 +0200
@@ -3,7 +3,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.4
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -21,12 +21,29 @@
 	CONTROL_MAX_ELEMENTS = 32
 };
 
+enum {
+	CONTROL_RATE_44KHZ,
+	CONTROL_RATE_48KHZ,
+	CONTROL_RATE_88KHZ,
+	CONTROL_RATE_96KHZ,
+	CONTROL_RATE_176KHZ,
+	CONTROL_RATE_192KHZ,
+	CONTROL_N_RATES
+};
+
 struct control_runtime {
+	int (*update_streaming)(struct control_runtime *rt);
+	int (*set_rate)(struct control_runtime *rt, int rate);
+	int (*set_channels)(struct control_runtime *rt, int n_analog_out,
+		int n_analog_in, bool spdif_out, bool spdif_in);
+
 	struct sfire_chip *chip;
 
 	struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS];
 	bool opt_coax_switch;
 	bool line_phono_switch;
+	bool digital_thru_switch;
+	bool usb_streaming;
 	u8 master_vol;
 };
 
diff -Nur a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
--- a/sound/usb/6fire/firmware.c	2011-03-31 21:14:19.575972963 +0200
+++ b/sound/usb/6fire/firmware.c	2011-03-31 21:13:35.730973001 +0200
@@ -3,15 +3,9 @@
  *
  * Firmware loader
  *
- * Currently not working for all devices. To be able to use the device
- * in linux, it is also possible to let the windows driver upload the firmware.
- * For that, start the computer in windows and reboot.
- * As long as the device is connected to the power supply, no firmware reload
- * needs to be performed.
- *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.4
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -72,6 +66,10 @@
 	0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
 };
 
+static const u8 known_fw_versions[][4] = {
+	{ 0x03, 0x01, 0x0b, 0x00 }
+};
+
 struct ihex_record {
 	u16 address;
 	u8 len;
@@ -254,6 +252,7 @@
 	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);
 		return ret;
@@ -363,6 +362,25 @@
 	return 0;
 }
 
+/* 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)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
+		if (!memcmp(version, known_fw_versions, 4))
+			return 0;
+
+	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
+			"%02x %02x %02x %02x. "
+			"please reconnect to power. if this failure "
+			"still happens, check your firmware installation.",
+			version[0], version[1], version[2], version[3]);
+	return -EINVAL;
+}
+
 int usb6fire_fw_init(struct usb_interface *intf)
 {
 	int i;
@@ -378,9 +396,12 @@
 				"firmware state.\n");
 		return ret;
 	}
-	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55
-			|| buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7]
-			!= 0x00) {
+		snd_printk(KERN_ERR PREFIX "device firmware state"
+				": ");
+		for (i = 0; i < 8; i++)
+			snd_printk("%02x ", buffer[i]);
+		snd_printk("\n");
+	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 		snd_printk(KERN_ERR PREFIX "unknown device firmware state "
 				"received from device: ");
 		for (i = 0; i < 8; i++)
@@ -389,7 +410,7 @@
 		return -EIO;
 	}
 	/* do we need fpga loader ezusb firmware? */
-	if (buffer[3] == 0x01 && buffer[6] == 0x19) {
+	if (buffer[3] == 0x01) {
 		ret = usb6fire_fw_ezusb_upload(intf,
 				"6fire/dmx6firel2.ihx", 0, NULL, 0);
 		if (ret < 0)
@@ -397,7 +418,10 @@
 		return FW_NOT_READY;
 	}
 	/* do we need fpga firmware and application ezusb firmware? */
-	else if (buffer[3] == 0x02 && buffer[6] == 0x0b) {
+	else if (buffer[3] == 0x02) {
+		ret = usb6fire_fw_check(buffer + 4);
+		if (ret < 0)
+			return ret;
 		ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
 		if (ret < 0)
 			return ret;
@@ -410,8 +434,8 @@
 		return FW_NOT_READY;
 	}
 	/* all fw loaded? */
-	else if (buffer[3] == 0x03 && buffer[6] == 0x0b)
-		return 0;
+	else if (buffer[3] == 0x03)
+		return usb6fire_fw_check(buffer + 4);
 	/* unknown data? */
 	else {
 		snd_printk(KERN_ERR PREFIX "unknown device firmware state "
diff -Nur a/sound/usb/6fire/firmware.h b/sound/usb/6fire/firmware.h
--- a/sound/usb/6fire/firmware.h	2011-03-31 21:14:19.576972975 +0200
+++ b/sound/usb/6fire/firmware.h	2011-03-31 21:13:59.276973000 +0200
@@ -1,8 +1,9 @@
 /*
  * Linux driver for TerraTec DMX 6Fire USB
  *
- * Author: Torsten Schenk
- * Created: Jan 01, 2011
+ * Author:	Torsten Schenk
+ * 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 -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
--- a/sound/usb/6fire/pcm.c	2011-03-31 21:14:19.575972963 +0200
+++ b/sound/usb/6fire/pcm.c	2011-03-31 21:07:57.017973262 +0200
@@ -5,7 +5,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.4
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,26 +17,23 @@
 #include "pcm.h"
 #include "chip.h"
 #include "comm.h"
+#include "control.h"
 
 enum {
 	OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4
 };
 
 /* keep next two synced with
- * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
+ * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE
+ * and CONTROL_RATE_XXX in control.h */
 static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };
 static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };
 static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
-static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
 static const int rates_alsaid[] = {
 	SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,
 	SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
 	SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
 
-/* values to write to soundcard register for all samplerates */
-static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
-static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
-
 enum { /* settings for pcm */
 	OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024
 };
@@ -48,15 +45,6 @@
 	STREAM_STOPPING
 };
 
-enum { /* pcm sample rates (also index into RATES_XXX[]) */
-	RATE_44KHZ,
-	RATE_48KHZ,
-	RATE_88KHZ,
-	RATE_96KHZ,
-	RATE_176KHZ,
-	RATE_192KHZ
-};
-
 static const struct snd_pcm_hardware pcm_hw = {
 	.info = SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_INTERLEAVED |
@@ -64,7 +52,7 @@
 		SNDRV_PCM_INFO_MMAP_VALID |
 		SNDRV_PCM_INFO_BATCH,
 
-	.formats = SNDRV_PCM_FMTBIT_S24_LE,
+	.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
 
 	.rates = SNDRV_PCM_RATE_44100 |
 		SNDRV_PCM_RATE_48000 |
@@ -87,57 +75,34 @@
 static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
 {
 	int ret;
-	struct usb_device *device = rt->chip->dev;
-	struct comm_runtime *comm_rt = rt->chip->comm;
+	struct control_runtime *ctrl_rt = rt->chip->control;
 
-	if (rt->rate >= ARRAY_SIZE(rates))
-		return -EINVAL;
-	/* disable streaming */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00);
+	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]);
 		return ret;
 	}
 
-	ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]);
-	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error setting interface "
-				"altsetting %d for samplerate %d.\n",
-				rates_altsetting[rt->rate], rates[rt->rate]);
-		return ret;
-	}
-
-	/* set soundcard clock */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate],
-			rates_6fire_vh[rt->rate]);
+	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]);
 		return ret;
 	}
 
-	/* enable analog inputs and outputs
-	 * (one bit per stereo-channel) */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
-			(1 << (OUT_N_CHANNELS / 2)) - 1,
-			(1 << (IN_N_CHANNELS / 2)) - 1);
+	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 analog channels "
+		snd_printk(KERN_ERR PREFIX "error initializing channels "
 				"while setting samplerate %d.\n",
 				rates[rt->rate]);
 		return ret;
 	}
-	/* disable digital inputs and outputs */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
-	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error initializing digital "
-				"channels while setting samplerate %d.\n",
-				rates[rt->rate]);
-		return ret;
-	}
 
-	ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01);
+	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]);
@@ -168,12 +133,15 @@
 static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
 {
 	int i;
+	struct control_runtime *ctrl_rt = rt->chip->control;
 
 	if (rt->stream_state != STREAM_DISABLED) {
 		for (i = 0; i < PCM_N_URBS; i++) {
 			usb_kill_urb(&rt->in_urbs[i].instance);
 			usb_kill_urb(&rt->out_urbs[i].instance);
 		}
+		ctrl_rt->usb_streaming = false;
+		ctrl_rt->update_streaming(ctrl_rt);
 		rt->stream_state = STREAM_DISABLED;
 	}
 }
@@ -228,7 +196,7 @@
 	unsigned int total_length = 0;
 	struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
 	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
-	u32 *src = (u32 *) urb->buffer;
+	u32 *src = NULL;
 	u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
 			* (alsa_rt->frame_bits >> 3));
 	u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
@@ -244,7 +212,12 @@
 		else
 			frame_count = 0;
 
-		src = (u32 *) (urb->buffer + total_length);
+		if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+			src = (u32 *) (urb->buffer + total_length);
+		else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+			src = (u32 *) (urb->buffer - 1 + total_length);
+		else
+			return;
 		src++; /* skip leading 4 bytes of every packet */
 		total_length += urb->packets[i].length;
 		for (frame = 0; frame < frame_count; frame++) {
@@ -274,9 +247,18 @@
 			* (alsa_rt->frame_bits >> 3));
 	u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
 			* (alsa_rt->frame_bits >> 3));
-	u32 *dest = (u32 *) urb->buffer;
+	u32 *dest;
 	int bytes_per_frame = alsa_rt->channels << 2;
 
+	if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+		dest = (u32 *) (urb->buffer - 1);
+	else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+		dest = (u32 *) (urb->buffer);
+	else {
+		snd_printk(KERN_ERR PREFIX "Unknown sample format.");
+		return;
+	}
+
 	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
 		/* at least 4 header bytes for valid packet.
 		 * after that: 32 bits per sample for analog channels */
@@ -480,7 +462,6 @@
 	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
 	struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
 	struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
-	int i;
 	int ret;
 
 	if (rt->panic)
@@ -493,12 +474,10 @@
 	sub->period_off = 0;
 
 	if (rt->stream_state == STREAM_DISABLED) {
-		for (i = 0; i < ARRAY_SIZE(rates); i++)
-			if (alsa_rt->rate == rates[i]) {
-				rt->rate = i;
+		for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++)
+			if (alsa_rt->rate == rates[rt->rate])
 				break;
-			}
-		if (i == ARRAY_SIZE(rates)) {
+		if (rt->rate == ARRAY_SIZE(rates)) {
 			mutex_unlock(&rt->stream_mutex);
 			snd_printk("invalid rate %d in prepare.\n",
 					alsa_rt->rate);
diff -Nur a/sound/usb/Kconfig b/sound/usb/Kconfig
--- a/sound/usb/Kconfig	2011-03-31 21:14:19.574972947 +0200
+++ b/sound/usb/Kconfig	2011-03-31 21:07:57.017973262 +0200
@@ -100,7 +100,6 @@
 
 config SND_USB_6FIRE
         tristate "TerraTec DMX 6Fire USB"
-        depends on EXPERIMENTAL
         select FW_LOADER
         select SND_RAWMIDI
         select SND_PCM
@@ -111,5 +111,3 @@
-          after it has been coldstarted. This driver currently does not support
-          firmware loading for all devices. If you own such a device,
-          you could start windows and let the windows driver upload
-          the firmware. As long as you do not unplug your device from power,
-          it should be usable.
+          after it has been coldstarted. An install script for the firmware
+          and further help can be found at
+          http://sixfireusb.sourceforge.net


[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: TerraTec DMX 6Fire USB updates
  2011-03-31 19:25         ` TerraTec DMX 6Fire USB updates Torsten Schenk
@ 2011-04-01 12:52           ` Takashi Iwai
  2011-04-03 12:30             ` Torsten Schenk
  2011-06-16 19:06             ` [PATCH] final issues in snd-usb-6fire concerning signedness bug Torsten Schenk
  0 siblings, 2 replies; 22+ messages in thread
From: Takashi Iwai @ 2011-04-01 12:52 UTC (permalink / raw)
  To: Torsten Schenk; +Cc: alsa-devel, clemens

At Thu, 31 Mar 2011 21:25:23 +0200,
Torsten Schenk wrote:
> 
> Hello everyone,
> 
> The driver I wrote for the 6fire usb is now in use by some people so that I got feedback. This enabled me to improve and bugfix some things. Here the patch.

Could you give a bit more information, what does your patch fix exactly?
This must be written in the changelog.


thanks,

Takashi

> +static int usb6fire_control_digital_thru_info(struct snd_kcontrol *kcontrol,
> +		struct snd_ctl_elem_info *uinfo)
> +{
> +	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
> +	uinfo->count = 1;
> +	uinfo->value.integer.min = 0;
> +	uinfo->value.integer.max = 1;
> +	return 0;
> +}

Use the common snd_ctl_boolean_mono_info() instead.


> +/* 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)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
> +		if (!memcmp(version, known_fw_versions, 4))

No increment or indexing (although there is only one element for now)?


thanks,

Takashi

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: TerraTec DMX 6Fire USB updates
  2011-04-01 12:52           ` Takashi Iwai
@ 2011-04-03 12:30             ` Torsten Schenk
  2011-04-04  7:28               ` Takashi Iwai
  2011-06-16 19:06             ` [PATCH] final issues in snd-usb-6fire concerning signedness bug Torsten Schenk
  1 sibling, 1 reply; 22+ messages in thread
From: Torsten Schenk @ 2011-04-03 12:30 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

[-- Attachment #1: Type: text/plain, Size: 827 bytes --]

Ok, fixed your two issues. Here the changelog and the patch again:

- control: digital thru added (for conversion optical<->tos)
- restructuring: samplerate, channel and streaming control moved to control.c
- firmware loader: loader now accepts all hardware versions of the device
- firmware loader: if firmware is already present it will be accepted if it is known to be working
- pcm: added support for s32_le sampleformat
- makefile: "experimental" dependency removed (tested and confirmed by users on http://sixfireusb.sourceforge.net)
- makefile: description updated
- bugfix: unsigned pcm_runtime.rate now never uses negative values (completion of signedness bug correction submitted by Dan Carpenter)
- bugfix: firmware leak fixed if error occurs (already submitted by Jesper Juhl but not in kernel yet)

Thanks
Torsten

[-- Attachment #2: usb6fire.patch --]
[-- Type: application/octet-stream, Size: 19592 bytes --]

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

diff -Nur a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
--- a/sound/usb/6fire/chip.c	2011-03-31 21:20:22.634973287 +0200
+++ b/sound/usb/6fire/chip.c	2011-04-03 14:08:29.753369038 +0200
@@ -5,7 +5,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.5
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,7 @@
 #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, version 0.3.5");
 MODULE_LICENSE("GPL v2");
 MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
 
diff -Nur a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
--- a/sound/usb/6fire/control.c	2011-03-31 21:20:22.633973308 +0200
+++ b/sound/usb/6fire/control.c	2011-04-02 05:40:48.812252998 +0200
@@ -5,7 +5,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.5
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -65,6 +65,15 @@
 	{ 0 } /* TERMINATING ENTRY */
 };
 
+static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
+/* values to write to soundcard register for all samplerates */
+static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
+static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
+
+enum {
+	DIGITAL_THRU_ONLY_SAMPLERATE = 3
+};
+
 static void usb6fire_control_master_vol_update(struct control_runtime *rt)
 {
 	struct comm_runtime *comm_rt = rt->chip->comm;
@@ -95,6 +104,67 @@
 	}
 }
 
+static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
+{
+	int ret;
+	struct usb_device *device = rt->chip->dev;
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (rate < 0 || rate >= CONTROL_N_RATES)
+		return -EINVAL;
+
+	ret = usb_set_interface(device, 1, rates_altsetting[rate]);
+	if (ret < 0)
+		return ret;
+
+	/* set soundcard clock */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
+			rates_6fire_vh[rate]);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int usb6fire_control_set_channels(
+	struct control_runtime *rt, int n_analog_out,
+	int n_analog_in, bool spdif_out, bool spdif_in)
+{
+	int ret;
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	/* enable analog inputs and outputs
+	 * (one bit per stereo-channel) */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
+			(1 << (n_analog_out / 2)) - 1,
+			(1 << (n_analog_in / 2)) - 1);
+	if (ret < 0)
+		return ret;
+
+	/* disable digital inputs and outputs */
+	/* TODO: use spdif_x to enable/disable digital channels */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int usb6fire_control_streaming_update(struct control_runtime *rt)
+{
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (comm_rt) {
+		if (!rt->usb_streaming && rt->digital_thru_switch)
+			usb6fire_control_set_rate(rt,
+				DIGITAL_THRU_ONLY_SAMPLERATE);
+		return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
+			(rt->usb_streaming ? 0x01 : 0x00) |
+			(rt->digital_thru_switch ? 0x08 : 0x00));
+	}
+	return -EINVAL;
+}
+
 static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_info *uinfo)
 {
@@ -195,6 +265,28 @@
 	return 0;
 }
 
+static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+
+	if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
+		rt->digital_thru_switch = ucontrol->value.integer.value[0];
+		usb6fire_control_streaming_update(rt);
+		changed = 1;
+	}
+	return changed;
+}
+
+static int usb6fire_control_digital_thru_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->digital_thru_switch;
+	return 0;
+}
+
 static struct __devinitdata snd_kcontrol_new elements[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -223,6 +315,15 @@
 		.get = usb6fire_control_opt_coax_get,
 		.put = usb6fire_control_opt_coax_put
 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Digital Thru Playback Route",
+		.index = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = snd_ctl_boolean_mono_info,
+		.get = usb6fire_control_digital_thru_get,
+		.put = usb6fire_control_digital_thru_put
+	},
 	{}
 };
 
@@ -238,6 +339,9 @@
 		return -ENOMEM;
 
 	rt->chip = chip;
+	rt->update_streaming = usb6fire_control_streaming_update;
+	rt->set_rate = usb6fire_control_set_rate;
+	rt->set_channels = usb6fire_control_set_channels;
 
 	i = 0;
 	while (init_data[i].type) {
@@ -249,6 +353,7 @@
 	usb6fire_control_opt_coax_update(rt);
 	usb6fire_control_line_phono_update(rt);
 	usb6fire_control_master_vol_update(rt);
+	usb6fire_control_streaming_update(rt);
 
 	i = 0;
 	while (elements[i].name) {
diff -Nur a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h
--- a/sound/usb/6fire/control.h	2011-03-31 21:20:22.633973308 +0200
+++ b/sound/usb/6fire/control.h	2011-03-31 21:07:57.018973241 +0200
@@ -3,7 +3,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.4
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -21,12 +21,29 @@
 	CONTROL_MAX_ELEMENTS = 32
 };
 
+enum {
+	CONTROL_RATE_44KHZ,
+	CONTROL_RATE_48KHZ,
+	CONTROL_RATE_88KHZ,
+	CONTROL_RATE_96KHZ,
+	CONTROL_RATE_176KHZ,
+	CONTROL_RATE_192KHZ,
+	CONTROL_N_RATES
+};
+
 struct control_runtime {
+	int (*update_streaming)(struct control_runtime *rt);
+	int (*set_rate)(struct control_runtime *rt, int rate);
+	int (*set_channels)(struct control_runtime *rt, int n_analog_out,
+		int n_analog_in, bool spdif_out, bool spdif_in);
+
 	struct sfire_chip *chip;
 
 	struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS];
 	bool opt_coax_switch;
 	bool line_phono_switch;
+	bool digital_thru_switch;
+	bool usb_streaming;
 	u8 master_vol;
 };
 
diff -Nur a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
--- a/sound/usb/6fire/firmware.c	2011-03-31 21:20:22.633973308 +0200
+++ b/sound/usb/6fire/firmware.c	2011-04-02 05:41:04.483252999 +0200
@@ -3,15 +3,9 @@
  *
  * Firmware loader
  *
- * Currently not working for all devices. To be able to use the device
- * in linux, it is also possible to let the windows driver upload the firmware.
- * For that, start the computer in windows and reboot.
- * As long as the device is connected to the power supply, no firmware reload
- * needs to be performed.
- *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.5
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -72,6 +66,10 @@
 	0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
 };
 
+static const u8 known_fw_versions[][4] = {
+	{ 0x03, 0x01, 0x0b, 0x00 }
+};
+
 struct ihex_record {
 	u16 address;
 	u8 len;
@@ -254,6 +252,7 @@
 	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);
 		return ret;
@@ -363,6 +362,25 @@
 	return 0;
 }
 
+/* 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)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
+		if (!memcmp(version, known_fw_versions + i, 4))
+			return 0;
+
+	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
+			"%02x %02x %02x %02x. "
+			"please reconnect to power. if this failure "
+			"still happens, check your firmware installation.",
+			version[0], version[1], version[2], version[3]);
+	return -EINVAL;
+}
+
 int usb6fire_fw_init(struct usb_interface *intf)
 {
 	int i;
@@ -378,9 +396,12 @@
 				"firmware state.\n");
 		return ret;
 	}
-	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55
-			|| buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7]
-			!= 0x00) {
+		snd_printk(KERN_ERR PREFIX "device firmware state"
+				": ");
+		for (i = 0; i < 8; i++)
+			snd_printk("%02x ", buffer[i]);
+		snd_printk("\n");
+	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 		snd_printk(KERN_ERR PREFIX "unknown device firmware state "
 				"received from device: ");
 		for (i = 0; i < 8; i++)
@@ -389,7 +410,7 @@
 		return -EIO;
 	}
 	/* do we need fpga loader ezusb firmware? */
-	if (buffer[3] == 0x01 && buffer[6] == 0x19) {
+	if (buffer[3] == 0x01) {
 		ret = usb6fire_fw_ezusb_upload(intf,
 				"6fire/dmx6firel2.ihx", 0, NULL, 0);
 		if (ret < 0)
@@ -397,7 +418,10 @@
 		return FW_NOT_READY;
 	}
 	/* do we need fpga firmware and application ezusb firmware? */
-	else if (buffer[3] == 0x02 && buffer[6] == 0x0b) {
+	else if (buffer[3] == 0x02) {
+		ret = usb6fire_fw_check(buffer + 4);
+		if (ret < 0)
+			return ret;
 		ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
 		if (ret < 0)
 			return ret;
@@ -410,8 +434,8 @@
 		return FW_NOT_READY;
 	}
 	/* all fw loaded? */
-	else if (buffer[3] == 0x03 && buffer[6] == 0x0b)
-		return 0;
+	else if (buffer[3] == 0x03)
+		return usb6fire_fw_check(buffer + 4);
 	/* unknown data? */
 	else {
 		snd_printk(KERN_ERR PREFIX "unknown device firmware state "
diff -Nur a/sound/usb/6fire/firmware.h b/sound/usb/6fire/firmware.h
--- a/sound/usb/6fire/firmware.h	2011-03-31 21:20:22.634973287 +0200
+++ b/sound/usb/6fire/firmware.h	2011-03-31 21:13:59.276973000 +0200
@@ -1,8 +1,9 @@
 /*
  * Linux driver for TerraTec DMX 6Fire USB
  *
- * Author: Torsten Schenk
- * Created: Jan 01, 2011
+ * Author:	Torsten Schenk
+ * 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 -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
--- a/sound/usb/6fire/pcm.c	2011-03-31 21:20:22.632973329 +0200
+++ b/sound/usb/6fire/pcm.c	2011-04-02 05:40:58.672253000 +0200
@@ -5,7 +5,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.5
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,26 +17,23 @@
 #include "pcm.h"
 #include "chip.h"
 #include "comm.h"
+#include "control.h"
 
 enum {
 	OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4
 };
 
 /* keep next two synced with
- * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
+ * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE
+ * and CONTROL_RATE_XXX in control.h */
 static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };
 static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };
 static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
-static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
 static const int rates_alsaid[] = {
 	SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,
 	SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
 	SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
 
-/* values to write to soundcard register for all samplerates */
-static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
-static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
-
 enum { /* settings for pcm */
 	OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024
 };
@@ -48,15 +45,6 @@
 	STREAM_STOPPING
 };
 
-enum { /* pcm sample rates (also index into RATES_XXX[]) */
-	RATE_44KHZ,
-	RATE_48KHZ,
-	RATE_88KHZ,
-	RATE_96KHZ,
-	RATE_176KHZ,
-	RATE_192KHZ
-};
-
 static const struct snd_pcm_hardware pcm_hw = {
 	.info = SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_INTERLEAVED |
@@ -64,7 +52,7 @@
 		SNDRV_PCM_INFO_MMAP_VALID |
 		SNDRV_PCM_INFO_BATCH,
 
-	.formats = SNDRV_PCM_FMTBIT_S24_LE,
+	.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
 
 	.rates = SNDRV_PCM_RATE_44100 |
 		SNDRV_PCM_RATE_48000 |
@@ -87,57 +75,34 @@
 static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
 {
 	int ret;
-	struct usb_device *device = rt->chip->dev;
-	struct comm_runtime *comm_rt = rt->chip->comm;
+	struct control_runtime *ctrl_rt = rt->chip->control;
 
-	if (rt->rate >= ARRAY_SIZE(rates))
-		return -EINVAL;
-	/* disable streaming */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00);
+	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]);
 		return ret;
 	}
 
-	ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]);
-	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error setting interface "
-				"altsetting %d for samplerate %d.\n",
-				rates_altsetting[rt->rate], rates[rt->rate]);
-		return ret;
-	}
-
-	/* set soundcard clock */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate],
-			rates_6fire_vh[rt->rate]);
+	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]);
 		return ret;
 	}
 
-	/* enable analog inputs and outputs
-	 * (one bit per stereo-channel) */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
-			(1 << (OUT_N_CHANNELS / 2)) - 1,
-			(1 << (IN_N_CHANNELS / 2)) - 1);
+	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 analog channels "
+		snd_printk(KERN_ERR PREFIX "error initializing channels "
 				"while setting samplerate %d.\n",
 				rates[rt->rate]);
 		return ret;
 	}
-	/* disable digital inputs and outputs */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
-	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error initializing digital "
-				"channels while setting samplerate %d.\n",
-				rates[rt->rate]);
-		return ret;
-	}
 
-	ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01);
+	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]);
@@ -168,12 +133,15 @@
 static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
 {
 	int i;
+	struct control_runtime *ctrl_rt = rt->chip->control;
 
 	if (rt->stream_state != STREAM_DISABLED) {
 		for (i = 0; i < PCM_N_URBS; i++) {
 			usb_kill_urb(&rt->in_urbs[i].instance);
 			usb_kill_urb(&rt->out_urbs[i].instance);
 		}
+		ctrl_rt->usb_streaming = false;
+		ctrl_rt->update_streaming(ctrl_rt);
 		rt->stream_state = STREAM_DISABLED;
 	}
 }
@@ -228,7 +196,7 @@
 	unsigned int total_length = 0;
 	struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
 	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
-	u32 *src = (u32 *) urb->buffer;
+	u32 *src = NULL;
 	u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
 			* (alsa_rt->frame_bits >> 3));
 	u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
@@ -244,7 +212,12 @@
 		else
 			frame_count = 0;
 
-		src = (u32 *) (urb->buffer + total_length);
+		if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+			src = (u32 *) (urb->buffer + total_length);
+		else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+			src = (u32 *) (urb->buffer - 1 + total_length);
+		else
+			return;
 		src++; /* skip leading 4 bytes of every packet */
 		total_length += urb->packets[i].length;
 		for (frame = 0; frame < frame_count; frame++) {
@@ -274,9 +247,18 @@
 			* (alsa_rt->frame_bits >> 3));
 	u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
 			* (alsa_rt->frame_bits >> 3));
-	u32 *dest = (u32 *) urb->buffer;
+	u32 *dest;
 	int bytes_per_frame = alsa_rt->channels << 2;
 
+	if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+		dest = (u32 *) (urb->buffer - 1);
+	else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+		dest = (u32 *) (urb->buffer);
+	else {
+		snd_printk(KERN_ERR PREFIX "Unknown sample format.");
+		return;
+	}
+
 	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
 		/* at least 4 header bytes for valid packet.
 		 * after that: 32 bits per sample for analog channels */
@@ -456,7 +438,7 @@
 		/* all substreams closed? if so, stop streaming */
 		if (!rt->playback.instance && !rt->capture.instance) {
 			usb6fire_pcm_stream_stop(rt);
-			rt->rate = -1;
+			rt->rate = ARRAY_SIZE(rates);
 		}
 	}
 	mutex_unlock(&rt->stream_mutex);
@@ -480,7 +462,6 @@
 	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
 	struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
 	struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
-	int i;
 	int ret;
 
 	if (rt->panic)
@@ -493,12 +474,10 @@
 	sub->period_off = 0;
 
 	if (rt->stream_state == STREAM_DISABLED) {
-		for (i = 0; i < ARRAY_SIZE(rates); i++)
-			if (alsa_rt->rate == rates[i]) {
-				rt->rate = i;
+		for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++)
+			if (alsa_rt->rate == rates[rt->rate])
 				break;
-			}
-		if (i == ARRAY_SIZE(rates)) {
+		if (rt->rate == ARRAY_SIZE(rates)) {
 			mutex_unlock(&rt->stream_mutex);
 			snd_printk("invalid rate %d in prepare.\n",
 					alsa_rt->rate);
@@ -613,7 +592,7 @@
 
 	rt->chip = chip;
 	rt->stream_state = STREAM_DISABLED;
-	rt->rate = -1;
+	rt->rate = ARRAY_SIZE(rates);
 	init_waitqueue_head(&rt->stream_wait_queue);
 	mutex_init(&rt->stream_mutex);
 
diff -Nur a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h
--- a/sound/usb/6fire/pcm.h	2011-03-31 21:20:22.633973308 +0200
+++ b/sound/usb/6fire/pcm.h	2011-04-02 05:40:52.960252998 +0200
@@ -3,7 +3,7 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
+ * Version:	0.3.5
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -65,7 +65,7 @@
 
 	struct mutex stream_mutex;
 	u8 stream_state; /* one of STREAM_XXX (pcm.c) */
-	u8 rate; /* one of PCM_RATE_XXX */
+	u8 rate; /* one of PCM_RATE_XXX or ARRAY_SIZE(rates) if invalid */
 	wait_queue_head_t stream_wait_queue;
 	bool stream_wait_cond;
 };
diff -Nur a/sound/usb/Kconfig b/sound/usb/Kconfig
--- a/sound/usb/Kconfig	2011-03-31 21:20:22.632973329 +0200
+++ b/sound/usb/Kconfig	2011-03-31 21:07:57.017973262 +0200
@@ -100,7 +100,6 @@
 
 config SND_USB_6FIRE
         tristate "TerraTec DMX 6Fire USB"
-        depends on EXPERIMENTAL
         select FW_LOADER
         select SND_RAWMIDI
         select SND_PCM
@@ -111,5 +111,3 @@
           Say Y here to include support for TerraTec 6fire DMX USB interface.
 
           You will need firmware files in order to be able to use the device
-          after it has been coldstarted. This driver currently does not support
-          firmware loading for all devices. If you own such a device,
-          you could start windows and let the windows driver upload
-          the firmware. As long as you do not unplug your device from power,
-          it should be usable.
+          after it has been coldstarted. An install script for the firmware
+          and further help can be found at
+          http://sixfireusb.sourceforge.net
 
 endif	# SND_USB
 

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: TerraTec DMX 6Fire USB updates
  2011-04-03 12:30             ` Torsten Schenk
@ 2011-04-04  7:28               ` Takashi Iwai
  2011-04-04  9:41                 ` Torsten Schenk
                                   ` (5 more replies)
  0 siblings, 6 replies; 22+ messages in thread
From: Takashi Iwai @ 2011-04-04  7:28 UTC (permalink / raw)
  To: Torsten Schenk; +Cc: alsa-devel, clemens

At Sun, 03 Apr 2011 14:30:43 +0200,
Torsten Schenk wrote:
> 
> Ok, fixed your two issues. Here the changelog and the patch again:
> 
> - control: digital thru added (for conversion optical<->tos)
> - restructuring: samplerate, channel and streaming control moved to control.c
> - firmware loader: loader now accepts all hardware versions of the device
> - firmware loader: if firmware is already present it will be accepted if it is known to be working
> - pcm: added support for s32_le sampleformat
> - makefile: "experimental" dependency removed (tested and confirmed by users on http://sixfireusb.sourceforge.net)
> - makefile: description updated
> - bugfix: unsigned pcm_runtime.rate now never uses negative values (completion of signedness bug correction submitted by Dan Carpenter)
> - bugfix: firmware leak fixed if error occurs (already submitted by Jesper Juhl but not in kernel yet)

Thanks.  But, as you see, there are too many changes done in a single
patch.  Could you split the changes into several incremental patches?
In principle, one patch should contain one change.  Of course, some
trivial changes can be merged, but the above is way too much.


Takashi

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: TerraTec DMX 6Fire USB updates
  2011-04-04  7:28               ` Takashi Iwai
@ 2011-04-04  9:41                 ` Torsten Schenk
  2011-04-04  9:45                 ` [PATCH 1/5] " Torsten Schenk
                                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 22+ messages in thread
From: Torsten Schenk @ 2011-04-04  9:41 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

>Thanks. But, as you see, there are too many changes done in a single 
>patch. Could you split the changes into several incremental patches? 
>In principle, one patch should contain one change. Of course, some 
>trivial changes can be merged, but the above is way too much. 

Ok, got how it's done.

For the following patches be working correctly, please apply the patch previously supplied by Jesper Juhl ("Don't leak firmware when
usb6fire_fw_ihex_init() fails.") before if missing... I downloaded the current kernel and this patch didn't seem to be applied.

Thanks,
Torsten

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/5] TerraTec DMX 6Fire USB updates
  2011-04-04  7:28               ` Takashi Iwai
  2011-04-04  9:41                 ` Torsten Schenk
@ 2011-04-04  9:45                 ` Torsten Schenk
  2011-04-04 10:29                   ` Takashi Iwai
  2011-04-04  9:47                 ` [PATCH 2/5] " Torsten Schenk
                                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 22+ messages in thread
From: Torsten Schenk @ 2011-04-04  9:45 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

Kernel configuration updated:
- experimental dependency removed
- description updated

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

diff -Nur a/sound/usb/Kconfig b/sound/usb/Kconfig
--- a/sound/usb/Kconfig	2011-03-31 21:20:22.000000000 +0200
+++ b/sound/usb/Kconfig	2011-03-31 21:07:57.000000000 +0200
@@ -100,7 +100,6 @@
 
 config SND_USB_6FIRE
         tristate "TerraTec DMX 6Fire USB"
-        depends on EXPERIMENTAL
         select FW_LOADER
         select SND_RAWMIDI
         select SND_PCM
@@ -111,5 +111,3 @@
-          after it has been coldstarted. This driver currently does not support
-          firmware loading for all devices. If you own such a device,
-          you could start windows and let the windows driver upload
-          the firmware. As long as you do not unplug your device from power,
-          it should be usable.
+          after it has been coldstarted. An install script for the firmware
+          and further help can be found at
+          http://sixfireusb.sourceforge.net

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 2/5] TerraTec DMX 6Fire USB updates
  2011-04-04  7:28               ` Takashi Iwai
  2011-04-04  9:41                 ` Torsten Schenk
  2011-04-04  9:45                 ` [PATCH 1/5] " Torsten Schenk
@ 2011-04-04  9:47                 ` Torsten Schenk
  2011-04-04  9:49                 ` [PATCH 3/5] " Torsten Schenk
                                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 22+ messages in thread
From: Torsten Schenk @ 2011-04-04  9:47 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

Completion of signedness bug for pcm_runtime.rate: variable will never get assigned a negative value now.

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
--- a/sound/usb/6fire/pcm.c	2011-04-04 11:17:56.469832999 +0200
+++ b/sound/usb/6fire/pcm.c	2011-04-04 11:23:12.993833002 +0200
@@ -456,7 +456,7 @@
 		/* all substreams closed? if so, stop streaming */
 		if (!rt->playback.instance && !rt->capture.instance) {
 			usb6fire_pcm_stream_stop(rt);
-			rt->rate = -1;
+			rt->rate = ARRAY_SIZE(rates);
 		}
 	}
 	mutex_unlock(&rt->stream_mutex);
@@ -480,7 +480,6 @@
 	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
 	struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
 	struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
-	int i;
 	int ret;
 
 	if (rt->panic)
@@ -493,12 +492,10 @@
 	sub->period_off = 0;
 
 	if (rt->stream_state == STREAM_DISABLED) {
-		for (i = 0; i < ARRAY_SIZE(rates); i++)
-			if (alsa_rt->rate == rates[i]) {
-				rt->rate = i;
+		for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++)
+			if (alsa_rt->rate == rates[rt->rate])
 				break;
-			}
-		if (i == ARRAY_SIZE(rates)) {
+		if (rt->rate == ARRAY_SIZE(rates)) {
 			mutex_unlock(&rt->stream_mutex);
 			snd_printk("invalid rate %d in prepare.\n",
 					alsa_rt->rate);
@@ -613,7 +610,7 @@
 
 	rt->chip = chip;
 	rt->stream_state = STREAM_DISABLED;
-	rt->rate = -1;
+	rt->rate = ARRAY_SIZE(rates);
 	init_waitqueue_head(&rt->stream_wait_queue);
 	mutex_init(&rt->stream_mutex);

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 3/5] TerraTec DMX 6Fire USB updates
  2011-04-04  7:28               ` Takashi Iwai
                                   ` (2 preceding siblings ...)
  2011-04-04  9:47                 ` [PATCH 2/5] " Torsten Schenk
@ 2011-04-04  9:49                 ` Torsten Schenk
  2011-04-04  9:49                 ` [PATCH 4/5] " Torsten Schenk
  2011-04-04  9:50                 ` [PATCH 5/5] " Torsten Schenk
  5 siblings, 0 replies; 22+ messages in thread
From: Torsten Schenk @ 2011-04-04  9:49 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

Added support for sample format s32_le.

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
--- a/sound/usb/6fire/pcm.c	2011-04-04 11:23:42.102833002 +0200
+++ b/sound/usb/6fire/pcm.c	2011-04-04 11:23:10.342833002 +0200
@@ -64,7 +64,7 @@
 		SNDRV_PCM_INFO_MMAP_VALID |
 		SNDRV_PCM_INFO_BATCH,
 
-	.formats = SNDRV_PCM_FMTBIT_S24_LE,
+	.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
 
 	.rates = SNDRV_PCM_RATE_44100 |
 		SNDRV_PCM_RATE_48000 |
@@ -228,7 +228,7 @@
 	unsigned int total_length = 0;
 	struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
 	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
-	u32 *src = (u32 *) urb->buffer;
+	u32 *src = NULL;
 	u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
 			* (alsa_rt->frame_bits >> 3));
 	u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
@@ -244,7 +244,12 @@
 		else
 			frame_count = 0;
 
-		src = (u32 *) (urb->buffer + total_length);
+		if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+			src = (u32 *) (urb->buffer + total_length);
+		else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+			src = (u32 *) (urb->buffer - 1 + total_length);
+		else
+			return;
 		src++; /* skip leading 4 bytes of every packet */
 		total_length += urb->packets[i].length;
 		for (frame = 0; frame < frame_count; frame++) {
@@ -274,9 +279,18 @@
 			* (alsa_rt->frame_bits >> 3));
 	u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
 			* (alsa_rt->frame_bits >> 3));
-	u32 *dest = (u32 *) urb->buffer;
+	u32 *dest;
 	int bytes_per_frame = alsa_rt->channels << 2;
 
+	if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)
+		dest = (u32 *) (urb->buffer - 1);
+	else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
+		dest = (u32 *) (urb->buffer);
+	else {
+		snd_printk(KERN_ERR PREFIX "Unknown sample format.");
+		return;
+	}
+
 	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
 		/* at least 4 header bytes for valid packet.
 		 * after that: 32 bits per sample for analog channels */

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 4/5] TerraTec DMX 6Fire USB updates
  2011-04-04  7:28               ` Takashi Iwai
                                   ` (3 preceding siblings ...)
  2011-04-04  9:49                 ` [PATCH 3/5] " Torsten Schenk
@ 2011-04-04  9:49                 ` Torsten Schenk
  2011-04-04  9:50                 ` [PATCH 5/5] " Torsten Schenk
  5 siblings, 0 replies; 22+ messages in thread
From: Torsten Schenk @ 2011-04-04  9:49 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

Firmware loader: magical device bytes check updated (accepts all device versions now and accepts possibly loaded firmware, if it is knowing to be working)

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

diff -Nur a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
--- a/sound/usb/6fire/firmware.c	2011-04-04 11:26:54.528833002 +0200
+++ b/sound/usb/6fire/firmware.c	2011-04-04 11:25:27.014833002 +0200
@@ -3,12 +3,6 @@
  *
  * Firmware loader
  *
- * Currently not working for all devices. To be able to use the device
- * in linux, it is also possible to let the windows driver upload the firmware.
- * For that, start the computer in windows and reboot.
- * As long as the device is connected to the power supply, no firmware reload
- * needs to be performed.
- *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
  * Version:	0.3.0
@@ -72,6 +66,10 @@
 	0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
 };
 
+static const u8 known_fw_versions[][4] = {
+	{ 0x03, 0x01, 0x0b, 0x00 }
+};
+
 struct ihex_record {
 	u16 address;
 	u8 len;
@@ -364,6 +362,25 @@
 	return 0;
 }
 
+/* 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)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
+		if (!memcmp(version, known_fw_versions + i, 4))
+			return 0;
+
+	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
+			"%02x %02x %02x %02x. "
+			"please reconnect to power. if this failure "
+			"still happens, check your firmware installation.",
+			version[0], version[1], version[2], version[3]);
+	return -EINVAL;
+}
+
 int usb6fire_fw_init(struct usb_interface *intf)
 {
 	int i;
@@ -379,9 +396,7 @@
 				"firmware state.\n");
 		return ret;
 	}
-	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55
-			|| buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7]
-			!= 0x00) {
+	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 		snd_printk(KERN_ERR PREFIX "unknown device firmware state "
 				"received from device: ");
 		for (i = 0; i < 8; i++)
@@ -390,7 +405,7 @@
 		return -EIO;
 	}
 	/* do we need fpga loader ezusb firmware? */
-	if (buffer[3] == 0x01 && buffer[6] == 0x19) {
+	if (buffer[3] == 0x01) {
 		ret = usb6fire_fw_ezusb_upload(intf,
 				"6fire/dmx6firel2.ihx", 0, NULL, 0);
 		if (ret < 0)
@@ -398,7 +413,10 @@
 		return FW_NOT_READY;
 	}
 	/* do we need fpga firmware and application ezusb firmware? */
-	else if (buffer[3] == 0x02 && buffer[6] == 0x0b) {
+	else if (buffer[3] == 0x02) {
+		ret = usb6fire_fw_check(buffer + 4);
+		if (ret < 0)
+			return ret;
 		ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
 		if (ret < 0)
 			return ret;
@@ -411,8 +429,8 @@
 		return FW_NOT_READY;
 	}
 	/* all fw loaded? */
-	else if (buffer[3] == 0x03 && buffer[6] == 0x0b)
-		return 0;
+	else if (buffer[3] == 0x03)
+		return usb6fire_fw_check(buffer + 4);
 	/* unknown data? */
 	else {
 		snd_printk(KERN_ERR PREFIX "unknown device firmware state "

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 5/5] TerraTec DMX 6Fire USB updates
  2011-04-04  7:28               ` Takashi Iwai
                                   ` (4 preceding siblings ...)
  2011-04-04  9:49                 ` [PATCH 4/5] " Torsten Schenk
@ 2011-04-04  9:50                 ` Torsten Schenk
  5 siblings, 0 replies; 22+ messages in thread
From: Torsten Schenk @ 2011-04-04  9:50 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

Digital Thru mixer element added (device can act as converter optical<->coax)

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

diff -Nur a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
--- a/sound/usb/6fire/control.c	2011-03-31 21:20:22.000000000 +0200
+++ b/sound/usb/6fire/control.c	2011-04-04 11:30:05.664833001 +0200
@@ -65,6 +65,15 @@
 	{ 0 } /* TERMINATING ENTRY */
 };
 
+static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
+/* values to write to soundcard register for all samplerates */
+static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
+static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
+
+enum {
+	DIGITAL_THRU_ONLY_SAMPLERATE = 3
+};
+
 static void usb6fire_control_master_vol_update(struct control_runtime *rt)
 {
 	struct comm_runtime *comm_rt = rt->chip->comm;
@@ -95,6 +104,67 @@
 	}
 }
 
+static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
+{
+	int ret;
+	struct usb_device *device = rt->chip->dev;
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (rate < 0 || rate >= CONTROL_N_RATES)
+		return -EINVAL;
+
+	ret = usb_set_interface(device, 1, rates_altsetting[rate]);
+	if (ret < 0)
+		return ret;
+
+	/* set soundcard clock */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
+			rates_6fire_vh[rate]);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int usb6fire_control_set_channels(
+	struct control_runtime *rt, int n_analog_out,
+	int n_analog_in, bool spdif_out, bool spdif_in)
+{
+	int ret;
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	/* enable analog inputs and outputs
+	 * (one bit per stereo-channel) */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
+			(1 << (n_analog_out / 2)) - 1,
+			(1 << (n_analog_in / 2)) - 1);
+	if (ret < 0)
+		return ret;
+
+	/* disable digital inputs and outputs */
+	/* TODO: use spdif_x to enable/disable digital channels */
+	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int usb6fire_control_streaming_update(struct control_runtime *rt)
+{
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (comm_rt) {
+		if (!rt->usb_streaming && rt->digital_thru_switch)
+			usb6fire_control_set_rate(rt,
+				DIGITAL_THRU_ONLY_SAMPLERATE);
+		return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
+			(rt->usb_streaming ? 0x01 : 0x00) |
+			(rt->digital_thru_switch ? 0x08 : 0x00));
+	}
+	return -EINVAL;
+}
+
 static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_info *uinfo)
 {
@@ -195,6 +265,28 @@
 	return 0;
 }
 
+static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+
+	if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
+		rt->digital_thru_switch = ucontrol->value.integer.value[0];
+		usb6fire_control_streaming_update(rt);
+		changed = 1;
+	}
+	return changed;
+}
+
+static int usb6fire_control_digital_thru_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->digital_thru_switch;
+	return 0;
+}
+
 static struct __devinitdata snd_kcontrol_new elements[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -223,6 +315,15 @@
 		.get = usb6fire_control_opt_coax_get,
 		.put = usb6fire_control_opt_coax_put
 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Digital Thru Playback Route",
+		.index = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = snd_ctl_boolean_mono_info,
+		.get = usb6fire_control_digital_thru_get,
+		.put = usb6fire_control_digital_thru_put
+	},
 	{}
 };
 
@@ -238,6 +339,9 @@
 		return -ENOMEM;
 
 	rt->chip = chip;
+	rt->update_streaming = usb6fire_control_streaming_update;
+	rt->set_rate = usb6fire_control_set_rate;
+	rt->set_channels = usb6fire_control_set_channels;
 
 	i = 0;
 	while (init_data[i].type) {
@@ -249,6 +353,7 @@
 	usb6fire_control_opt_coax_update(rt);
 	usb6fire_control_line_phono_update(rt);
 	usb6fire_control_master_vol_update(rt);
+	usb6fire_control_streaming_update(rt);
 
 	i = 0;
 	while (elements[i].name) {
diff -Nur a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h
--- a/sound/usb/6fire/control.h	2011-03-31 21:20:22.000000000 +0200
+++ b/sound/usb/6fire/control.h	2011-04-04 11:30:10.821833002 +0200
@@ -21,12 +21,29 @@
 	CONTROL_MAX_ELEMENTS = 32
 };
 
+enum {
+	CONTROL_RATE_44KHZ,
+	CONTROL_RATE_48KHZ,
+	CONTROL_RATE_88KHZ,
+	CONTROL_RATE_96KHZ,
+	CONTROL_RATE_176KHZ,
+	CONTROL_RATE_192KHZ,
+	CONTROL_N_RATES
+};
+
 struct control_runtime {
+	int (*update_streaming)(struct control_runtime *rt);
+	int (*set_rate)(struct control_runtime *rt, int rate);
+	int (*set_channels)(struct control_runtime *rt, int n_analog_out,
+		int n_analog_in, bool spdif_out, bool spdif_in);
+
 	struct sfire_chip *chip;
 
 	struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS];
 	bool opt_coax_switch;
 	bool line_phono_switch;
+	bool digital_thru_switch;
+	bool usb_streaming;
 	u8 master_vol;
 };
 
diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
--- a/sound/usb/6fire/pcm.c	2011-04-04 11:23:10.000000000 +0200
+++ b/sound/usb/6fire/pcm.c	2011-04-04 11:30:15.623833002 +0200
@@ -17,26 +17,23 @@
 #include "pcm.h"
 #include "chip.h"
 #include "comm.h"
+#include "control.h"
 
 enum {
 	OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4
 };
 
 /* keep next two synced with
- * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
+ * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE
+ * and CONTROL_RATE_XXX in control.h */
 static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };
 static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };
 static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
-static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
 static const int rates_alsaid[] = {
 	SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,
 	SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
 	SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
 
-/* values to write to soundcard register for all samplerates */
-static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
-static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
-
 enum { /* settings for pcm */
 	OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024
 };
@@ -48,15 +45,6 @@
 	STREAM_STOPPING
 };
 
-enum { /* pcm sample rates (also index into RATES_XXX[]) */
-	RATE_44KHZ,
-	RATE_48KHZ,
-	RATE_88KHZ,
-	RATE_96KHZ,
-	RATE_176KHZ,
-	RATE_192KHZ
-};
-
 static const struct snd_pcm_hardware pcm_hw = {
 	.info = SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_INTERLEAVED |
@@ -87,57 +75,34 @@
 static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
 {
 	int ret;
-	struct usb_device *device = rt->chip->dev;
-	struct comm_runtime *comm_rt = rt->chip->comm;
+	struct control_runtime *ctrl_rt = rt->chip->control;
 
-	if (rt->rate >= ARRAY_SIZE(rates))
-		return -EINVAL;
-	/* disable streaming */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00);
+	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]);
 		return ret;
 	}
 
-	ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]);
-	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error setting interface "
-				"altsetting %d for samplerate %d.\n",
-				rates_altsetting[rt->rate], rates[rt->rate]);
-		return ret;
-	}
-
-	/* set soundcard clock */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate],
-			rates_6fire_vh[rt->rate]);
+	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]);
 		return ret;
 	}
 
-	/* enable analog inputs and outputs
-	 * (one bit per stereo-channel) */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
-			(1 << (OUT_N_CHANNELS / 2)) - 1,
-			(1 << (IN_N_CHANNELS / 2)) - 1);
+	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 analog channels "
+		snd_printk(KERN_ERR PREFIX "error initializing channels "
 				"while setting samplerate %d.\n",
 				rates[rt->rate]);
 		return ret;
 	}
-	/* disable digital inputs and outputs */
-	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
-	if (ret < 0) {
-		snd_printk(KERN_ERR PREFIX "error initializing digital "
-				"channels while setting samplerate %d.\n",
-				rates[rt->rate]);
-		return ret;
-	}
 
-	ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01);
+	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]);
@@ -168,12 +133,15 @@
 static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
 {
 	int i;
+	struct control_runtime *ctrl_rt = rt->chip->control;
 
 	if (rt->stream_state != STREAM_DISABLED) {
 		for (i = 0; i < PCM_N_URBS; i++) {
 			usb_kill_urb(&rt->in_urbs[i].instance);
 			usb_kill_urb(&rt->out_urbs[i].instance);
 		}
+		ctrl_rt->usb_streaming = false;
+		ctrl_rt->update_streaming(ctrl_rt);
 		rt->stream_state = STREAM_DISABLED;
 	}
 }

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 1/5] TerraTec DMX 6Fire USB updates
  2011-04-04  9:45                 ` [PATCH 1/5] " Torsten Schenk
@ 2011-04-04 10:29                   ` Takashi Iwai
  0 siblings, 0 replies; 22+ messages in thread
From: Takashi Iwai @ 2011-04-04 10:29 UTC (permalink / raw)
  To: Torsten Schenk; +Cc: alsa-devel, clemens

At Mon, 04 Apr 2011 11:45:28 +0200,
Torsten Schenk wrote:
> 
> Kernel configuration updated:
> - experimental dependency removed
> - description updated
> 
> Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

Thanks, now applied all 5 patches to sound git tree (in topic/misc
branch). 

At the next time, please give more appropriate summary to each patch
corresponding to the content.


Takashi

> diff -Nur a/sound/usb/Kconfig b/sound/usb/Kconfig
> --- a/sound/usb/Kconfig	2011-03-31 21:20:22.000000000 +0200
> +++ b/sound/usb/Kconfig	2011-03-31 21:07:57.000000000 +0200
> @@ -100,7 +100,6 @@
>  
>  config SND_USB_6FIRE
>          tristate "TerraTec DMX 6Fire USB"
> -        depends on EXPERIMENTAL
>          select FW_LOADER
>          select SND_RAWMIDI
>          select SND_PCM
> @@ -111,5 +111,3 @@
> -          after it has been coldstarted. This driver currently does not support
> -          firmware loading for all devices. If you own such a device,
> -          you could start windows and let the windows driver upload
> -          the firmware. As long as you do not unplug your device from power,
> -          it should be usable.
> +          after it has been coldstarted. An install script for the firmware
> +          and further help can be found at
> +          http://sixfireusb.sourceforge.net
> 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH] final issues in snd-usb-6fire concerning signedness bug
  2011-04-01 12:52           ` Takashi Iwai
  2011-04-03 12:30             ` Torsten Schenk
@ 2011-06-16 19:06             ` Torsten Schenk
  2011-06-16 19:33               ` Takashi Iwai
  1 sibling, 1 reply; 22+ messages in thread
From: Torsten Schenk @ 2011-06-16 19:06 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

Fixed remaining issues of the signedness bug discovered by Dan Carpenter. A check was remaining that tests if unsigned rt->rate is >= 0. Changed that so that rt->rate now consistently uses ARRAY_SIZE(rates) as invalid rate value and not -1.


Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
--- a/sound/usb/6fire/pcm.c	2011-06-16 20:49:55.859600014 +0200
+++ b/sound/usb/6fire/pcm.c	2011-06-16 20:48:07.000000000 +0200
@@ -395,12 +395,12 @@
 	alsa_rt->hw = pcm_hw;
 
 	if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (rt->rate >= 0)
+		if (rt->rate < ARRAY_SIZE(rates))
 			alsa_rt->hw.rates = rates_alsaid[rt->rate];
 		alsa_rt->hw.channels_max = OUT_N_CHANNELS;
 		sub = &rt->playback;
 	} else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		if (rt->rate >= 0)
+		if (rt->rate < ARRAY_SIZE(rates))
 			alsa_rt->hw.rates = rates_alsaid[rt->rate];
 		alsa_rt->hw.channels_max = IN_N_CHANNELS;
 		sub = &rt->capture;

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] final issues in snd-usb-6fire concerning signedness bug
  2011-06-16 19:06             ` [PATCH] final issues in snd-usb-6fire concerning signedness bug Torsten Schenk
@ 2011-06-16 19:33               ` Takashi Iwai
  0 siblings, 0 replies; 22+ messages in thread
From: Takashi Iwai @ 2011-06-16 19:33 UTC (permalink / raw)
  To: Torsten Schenk; +Cc: alsa-devel, clemens

At Thu, 16 Jun 2011 21:06:27 +0200,
Torsten Schenk wrote:
> 
> Fixed remaining issues of the signedness bug discovered by Dan Carpenter. A check was remaining that tests if unsigned rt->rate is >= 0. Changed that so that rt->rate now consistently uses ARRAY_SIZE(rates) as invalid rate value and not -1.
> 
> 
> Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>

Thanks, applied now.
(But at the next, please give a bit better patch subject :)


Takashi

> diff -Nur a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
> --- a/sound/usb/6fire/pcm.c	2011-06-16 20:49:55.859600014 +0200
> +++ b/sound/usb/6fire/pcm.c	2011-06-16 20:48:07.000000000 +0200
> @@ -395,12 +395,12 @@
>  	alsa_rt->hw = pcm_hw;
>  
>  	if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> -		if (rt->rate >= 0)
> +		if (rt->rate < ARRAY_SIZE(rates))
>  			alsa_rt->hw.rates = rates_alsaid[rt->rate];
>  		alsa_rt->hw.channels_max = OUT_N_CHANNELS;
>  		sub = &rt->playback;
>  	} else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) {
> -		if (rt->rate >= 0)
> +		if (rt->rate < ARRAY_SIZE(rates))
>  			alsa_rt->hw.rates = rates_alsaid[rt->rate];
>  		alsa_rt->hw.channels_max = IN_N_CHANNELS;
>  		sub = &rt->capture;
> 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Driver for TerraTec DMX 6Fire USB
@ 2011-01-19 19:44 Torsten Schenk
  0 siblings, 0 replies; 22+ messages in thread
From: Torsten Schenk @ 2011-01-19 19:44 UTC (permalink / raw)
  To: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1202 bytes --]

Hello,

i recently got a TerraTec DMX 6Fire USB. Since it's not supported by alsa, I decided to look into communications between the windows driver and the card. Here is the result.

What should be revised:
- I was unsure about naming conventions, so please check the name of card/midi/pcm/control/module.
- Also the device needs firmware to be able to run. I did not included the firmware (from the windows driver) in the attachment since the 60kB mail size limit were exceeded last time I tried to post this driver.
- Firmware: I read about that .ihex-parsing in drivers is not really approved, but I cannot convert the files easily into a binary format because the offsets are not contiguous. Of course there could be alternate ways to be thought about, which would imply that original files from TT are not supported since they are in ihex.
- I didn't manage to create a configuration in /usr/share/alsa/cards.

What is working: Everything except SPDIF
- Hardware Master volume
- PCM 44-192kHz@24 bits, 6 channels out, 4 channels in (analog)
- MIDI in/out
- firmware loading after cold start
- phono/line switching

If anything else comes to your attention, just let me know.

Greetings, Torsten



[-- Attachment #2: 6fireusb.tar.bz2 --]
[-- Type: application/octet-stream, Size: 13189 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2011-06-16 19:33 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <12d995c1fa0.477955495632923443.5387390398635058860@zoho.com>
2011-01-20 16:54 ` Driver for TerraTec DMX 6Fire USB Takashi Iwai
2011-01-20 22:38   ` Torsten Schenk
2011-01-21  8:57     ` Takashi Iwai
2011-01-21 11:48       ` Torsten Schenk
2011-01-22 16:35         ` Takashi Iwai
2011-01-24 12:10           ` Torsten Schenk
2011-01-25 10:25             ` Takashi Iwai
2011-01-25 14:12               ` Torsten Schenk
2011-03-31 19:25         ` TerraTec DMX 6Fire USB updates Torsten Schenk
2011-04-01 12:52           ` Takashi Iwai
2011-04-03 12:30             ` Torsten Schenk
2011-04-04  7:28               ` Takashi Iwai
2011-04-04  9:41                 ` Torsten Schenk
2011-04-04  9:45                 ` [PATCH 1/5] " Torsten Schenk
2011-04-04 10:29                   ` Takashi Iwai
2011-04-04  9:47                 ` [PATCH 2/5] " Torsten Schenk
2011-04-04  9:49                 ` [PATCH 3/5] " Torsten Schenk
2011-04-04  9:49                 ` [PATCH 4/5] " Torsten Schenk
2011-04-04  9:50                 ` [PATCH 5/5] " Torsten Schenk
2011-06-16 19:06             ` [PATCH] final issues in snd-usb-6fire concerning signedness bug Torsten Schenk
2011-06-16 19:33               ` Takashi Iwai
2011-01-19 19:44 Driver for TerraTec DMX 6Fire USB Torsten Schenk

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.