[alsa-devel] [PATCH 1/7] ALSA: firewire-tascam: add skeleton for TASCAM FireWire series

Stefan Richter stefanr at s5r6.in-berlin.de
Sat Oct 3 12:33:33 CEST 2015


On Oct 03 Takashi Iwai wrote:
> On Sat, 03 Oct 2015 04:34:24 +0200,
> Takashi Sakamoto wrote:
> > 
> > Hi,
> > 
> > On Oct 13 2015 03:47, Clemens Ladisch wrote:
> > > Takashi Iwai wrote:
> > >> kbuild test robot wrote:
> > >>>>> sound/firewire/tascam/tascam.c:23:16: sparse: cast to restricted __be32
> > >>>
> > >>>   > 23		data = be32_to_cpu(fw_dev->config_rom[28]);
> > >>
> > >> The code itself looks correct.  data is CPU endian.
> > >> The problem looks rather like that fw_dev->config_rom[] is u32.
> > >>
> > >> Stefan, can it be changed to __be32 instead?
> > > 
> > > config_rom[] is CPU endian, too.
> > > 
> > > Strings should be read with fw_csr_string().
> > 
> > The function is designed for IEEE 1212 compliant config ROM. On the
> > other hand, config ROMs of these models are not fully compliant. See:
> > 
> > http://sourceforge.net/p/linux1394/mailman/message/33899800/
> > 
> > Currently, this driver supports just two models. These two models have
> > similar structure in their config ROM, fortunately. Thus, it's
> > reasonable for the driver to get information in hard-coded position of
> > config ROM.

You mention in the changelog that you support the models FW-1884 and
FW-1802, but that there is a third model which you cannot support yet due
to lack of information.  ---  Considering this limited number of models,
and if you are confident that there are no firmware revisions with
different config ROM offsets, then I agree that using hard-coded offsets
is a good way to retrieve the model-dependent information.

> > About using 'be32_to_cpu()', the 'config_rom' member actually has 'const
> > u32 *', while in the member caracters in the textual leaf are aligned in
> > big-endian. I selected the simplest way to pick it up.
> > 
> > If it's preferrable to suppress the sparse warnings, I don't mind to
> > replace these codes with the other ways.
> 
> Maybe introducing a macro would make things clearer.  It's better than
> open-coding at each place, in anyway.

I think it can all be made a lot simpler.  Quoting the patch 1/7:

+static const struct ieee1394_device_id snd_tscm_id_table[] = {
+	/* FW-1082 */
+	{
+		.match_flags = IEEE1394_MATCH_VENDOR_ID |
+			       IEEE1394_MATCH_SPECIFIER_ID |
+			       IEEE1394_MATCH_VERSION,
+		.vendor_id = 0x00022e,
+		.specifier_id = 0x00022e,
+		.version = 0x800003,
+	},
+	/* FW-1884 */
+	{
+		.match_flags = IEEE1394_MATCH_VENDOR_ID |
+			       IEEE1394_MATCH_SPECIFIER_ID |
+			       IEEE1394_MATCH_VERSION,
+		.vendor_id = 0x00022e,
+		.specifier_id = 0x00022e,
+		.version = 0x800000,
+	},
+	/* FW-1804 mey be supported if IDs are clear. */
+	/* FE-08 requires reverse-engineering because it just has faders. */
+	{}
+};

Since the driver is only matching devices with vendor ID 0x00022e, there is
IMO no need to verify the vendor name string in the Configuration ROM.

Do I understand correctly that the model name string needs to be checked
because we don't know yet whether the model FW-1804 contains an own "version"
or duplicates the "version" of FW-1802 or FW-1884?

In other words, if we knew that FW-1804 had a unique "version", then the
function check_name() would not be needed at all.

+static int check_name(struct snd_tscm *tscm)
+{
+	struct fw_device *fw_dev = fw_parent_device(tscm->unit);
+	char vendor[8];
+	char model[8];
+	__u32 data;
+
+	/* Retrieve model name. */
+	data = be32_to_cpu(fw_dev->config_rom[28]);
+	memcpy(model, &data, 4);
+	data = be32_to_cpu(fw_dev->config_rom[29]);
+	memcpy(model + 4, &data, 4);
+	model[7] = '\0';

The config_rom accesses need to be protected by an array bounds check.

The endian conversion actually needs to be the other way around:

	__be32 data;

	/*
	 * Retrieve model name from a bus_dependent_info leaf at
	 * the fixed ROM offsets [25...29], which is formed like a
	 * textual descriptor leaf in minimal ASCII format.
	 */
	data = cpu_to_be32(fw_dev->config_rom[28]);
	memcpy(model, &data, 4);
	data = cpu_to_be32(fw_dev->config_rom[29]);
	memcpy(model + 4, &data, 4);
	model[7] = '\0';

A mathematically equivalent way to code this can be seen in
drivers/firewire/core-device.c::textual_leaf_to_string():  This works
for arbitrary ROM offsets and with arbitrary string lengths.

+	/* Retrieve vendor name. */
+	data = be32_to_cpu(fw_dev->config_rom[23]);
+	memcpy(vendor, &data, 4);
+	data = be32_to_cpu(fw_dev->config_rom[24]);
+	memcpy(vendor + 4, &data, 4);
+	vendor[7] = '\0';

As I said, I think this is not needed since the driver does not deal
with devices from other vendors in the first place.

+	strcpy(tscm->card->driver, "FW-TASCAM");
+	strcpy(tscm->card->shortname, model);
+	strcpy(tscm->card->mixername, model);
+	snprintf(tscm->card->longname, sizeof(tscm->card->longname),
+		 "%s %s, GUID %08x%08x at %s, S%d", vendor, model,
+		 cpu_to_be32(fw_dev->config_rom[3]),
+		 cpu_to_be32(fw_dev->config_rom[4]),
+		 dev_name(&tscm->unit->device), 100 << fw_dev->max_speed);

The GUID needs to be printed without endian conversion:

	"GUID %08x%08x", fw_dev->config_rom[3], fw_dev->config_rom[4]

+	return 0;
+}

The function always returns 0 == no error, therefore it currently
fulfills no other purpose than to fill in card->{short,mixer,long}name.
It definitely does not actually check anything like the function name
suggests.  How about something like this:

/*
 * Retrieve model name from a bus_dependent_info leaf at the fixed ROM
 * offsets [25...29], which is formed like a textual descriptor leaf in
 * minimal ASCII format.
 */
static int check_model_name(struct snd_tscm *tscm)
{
	struct fw_device *fw_dev = fw_parent_device(tscm->unit);
	u32 rom28, rom29;
	const char *model;

	if (fw_dev->config_rom_length < 30) {
		dev_err(tscm->unit->device,
			"unknown Configuration ROM, too short\n"); 
		return -ENODEV;
	}

	rom28 = fw_dev->config_rom[28];
	rom29 = fw_dev->config_rom[29];

	if (rom28 == 0x46572d31 && rom29 == 0x30383200) {
		model = "FW-1082";
	} else if (rom28 == 0x46572d31 && rom29 == 0x38383400) {
		model = "FW-1884";
	} else {
		dev_err(tscm->unit->device,
			"unknown model %04x %04x\n", rom28, rom29);
		return -ENODEV;
	}

	strcpy(tscm->card->driver, "FW-TASCAM");
	strcpy(tscm->card->shortname, model);
	strcpy(tscm->card->mixername, model);
	snprintf(tscm->card->longname, sizeof(tscm->card->longname),
		 "TASCAM %s, GUID %08x%08x at %s, S%d", model,
		 fw_dev->config_rom[3], fw_dev->config_rom[4],
		 dev_name(&tscm->unit->device), 100 << fw_dev->max_speed);

	return 0;
}

Not compile-tested.
-- 
Stefan Richter
-=====-===== =-=- ---==
http://arcgraph.de/sr/


More information about the Alsa-devel mailing list