dice.c 8.2 KB
Newer Older
C
Clemens Ladisch 已提交
1 2 3 4 5 6 7
/*
 * TC Applied Technologies Digital Interface Communications Engine driver
 *
 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
 * Licensed under the terms of the GNU General Public License, version 2.
 */

8
#include "dice.h"
C
Clemens Ladisch 已提交
9 10 11 12 13

MODULE_DESCRIPTION("DICE driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL v2");

14 15 16 17
#define OUI_WEISS		0x001c6a

#define DICE_CATEGORY_ID	0x04
#define WEISS_CATEGORY_ID	0x00
18 19 20 21 22 23 24 25 26 27 28 29

static int dice_interface_check(struct fw_unit *unit)
{
	static const int min_values[10] = {
		10, 0x64 / 4,
		10, 0x18 / 4,
		10, 0x18 / 4,
		0, 0,
		0, 0,
	};
	struct fw_device *device = fw_parent_device(unit);
	struct fw_csr_iterator it;
30
	int key, val, vendor = -1, model = -1, err;
31
	unsigned int category, i;
32
	__be32 *pointers, value;
33 34
	__be32 version;

35 36 37 38 39
	pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
				 GFP_KERNEL);
	if (pointers == NULL)
		return -ENOMEM;

40 41 42
	/*
	 * Check that GUID and unit directory are constructed according to DICE
	 * rules, i.e., that the specifier ID is the GUID's OUI, and that the
43 44
	 * GUID chip ID consists of the 8-bit category ID, the 10-bit product
	 * ID, and a 22-bit serial number.
45 46
	 */
	fw_csr_iterator_init(&it, unit->directory);
47
	while (fw_csr_iterator_next(&it, &key, &val)) {
48 49
		switch (key) {
		case CSR_SPECIFIER_ID:
50
			vendor = val;
51 52
			break;
		case CSR_MODEL:
53
			model = val;
54 55 56
			break;
		}
	}
57 58 59 60 61
	if (vendor == OUI_WEISS)
		category = WEISS_CATEGORY_ID;
	else
		category = DICE_CATEGORY_ID;
	if (device->config_rom[3] != ((vendor << 8) | category) ||
62 63 64 65
	    device->config_rom[4] >> 22 != model) {
		err = -ENODEV;
		goto end;
	}
66 67 68 69 70 71 72

	/*
	 * Check that the sub address spaces exist and are located inside the
	 * private address space.  The minimum values are chosen so that all
	 * minimally required registers are included.
	 */
	err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
73 74 75 76 77 78 79
				 DICE_PRIVATE_SPACE, pointers,
				 sizeof(__be32) * ARRAY_SIZE(min_values), 0);
	if (err < 0) {
		err = -ENODEV;
		goto end;
	}
	for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
80
		value = be32_to_cpu(pointers[i]);
81 82 83 84
		if (value < min_values[i] || value >= 0x40000) {
			err = -ENODEV;
			goto end;
		}
85 86 87 88 89 90 91 92 93
	}

	/*
	 * Check that the implemented DICE driver specification major version
	 * number matches.
	 */
	err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
				 DICE_PRIVATE_SPACE +
				 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
94
				 &version, 4, 0);
95 96 97 98
	if (err < 0) {
		err = -ENODEV;
		goto end;
	}
99 100 101
	if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
		dev_err(&unit->device,
			"unknown DICE version: 0x%08x\n", be32_to_cpu(version));
102 103
		err = -ENODEV;
		goto end;
104
	}
105 106
end:
	return err;
107 108
}

109 110
static int highest_supported_mode_rate(struct snd_dice *dice,
				       unsigned int mode, unsigned int *rate)
111
{
112
	unsigned int i, m;
113

114 115 116 117 118 119 120 121 122
	for (i = ARRAY_SIZE(snd_dice_rates); i > 0; i--) {
		*rate = snd_dice_rates[i - 1];
		if (snd_dice_stream_get_rate_mode(dice, *rate, &m) < 0)
			continue;
		if (mode == m)
			break;
	}
	if (i == 0)
		return -EINVAL;
123

124
	return 0;
125 126
}

127
static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode)
128 129
{
	__be32 values[2];
130 131
	unsigned int rate;
	int err;
132

133
	if (highest_supported_mode_rate(dice, mode, &rate) < 0) {
134 135
		dice->tx_channels[mode] = 0;
		dice->tx_midi_ports[mode] = 0;
136 137 138 139 140
		dice->rx_channels[mode] = 0;
		dice->rx_midi_ports[mode] = 0;
		return 0;
	}

141
	err = snd_dice_transaction_set_rate(dice, rate);
142 143 144
	if (err < 0)
		return err;

145 146 147 148 149 150 151 152
	err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
					   values, sizeof(values));
	if (err < 0)
		return err;

	dice->tx_channels[mode]   = be32_to_cpu(values[0]);
	dice->tx_midi_ports[mode] = be32_to_cpu(values[1]);

153 154
	err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
					   values, sizeof(values));
155 156 157 158 159 160 161 162 163
	if (err < 0)
		return err;

	dice->rx_channels[mode]   = be32_to_cpu(values[0]);
	dice->rx_midi_ports[mode] = be32_to_cpu(values[1]);

	return 0;
}

164
static int dice_read_params(struct snd_dice *dice)
C
Clemens Ladisch 已提交
165
{
166
	__be32 value;
167
	int mode, err;
C
Clemens Ladisch 已提交
168

169
	/* some very old firmwares don't tell about their clock support */
170 171 172 173
	if (dice->clock_caps > 0) {
		err = snd_dice_transaction_read_global(dice,
						GLOBAL_CLOCK_CAPABILITIES,
						&value, 4);
174 175 176 177 178 179 180 181 182 183 184
		if (err < 0)
			return err;
		dice->clock_caps = be32_to_cpu(value);
	} else {
		/* this should be supported by any device */
		dice->clock_caps = CLOCK_CAP_RATE_44100 |
				   CLOCK_CAP_RATE_48000 |
				   CLOCK_CAP_SOURCE_ARX1 |
				   CLOCK_CAP_SOURCE_INTERNAL;
	}

185 186 187 188 189 190
	for (mode = 2; mode >= 0; --mode) {
		err = dice_read_mode_params(dice, mode);
		if (err < 0)
			return err;
	}

C
Clemens Ladisch 已提交
191 192 193
	return 0;
}

194
static void dice_card_strings(struct snd_dice *dice)
C
Clemens Ladisch 已提交
195 196 197 198 199 200 201 202 203 204 205
{
	struct snd_card *card = dice->card;
	struct fw_device *dev = fw_parent_device(dice->unit);
	char vendor[32], model[32];
	unsigned int i;
	int err;

	strcpy(card->driver, "DICE");

	strcpy(card->shortname, "DICE");
	BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
206 207 208
	err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME,
					       card->shortname,
					       sizeof(card->shortname));
C
Clemens Ladisch 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221
	if (err >= 0) {
		/* DICE strings are returned in "always-wrong" endianness */
		BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
		for (i = 0; i < sizeof(card->shortname); i += 4)
			swab32s((u32 *)&card->shortname[i]);
		card->shortname[sizeof(card->shortname) - 1] = '\0';
	}

	strcpy(vendor, "?");
	fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
	strcpy(model, "?");
	fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
	snprintf(card->longname, sizeof(card->longname),
222 223
		 "%s %s (serial %u) at %s, S%d",
		 vendor, model, dev->config_rom[4] & 0x3fffff,
C
Clemens Ladisch 已提交
224 225 226 227 228
		 dev_name(&dice->unit->device), 100 << dev->max_speed);

	strcpy(card->mixername, "DICE");
}

229 230 231 232 233 234 235 236
static void dice_card_free(struct snd_card *card)
{
	struct snd_dice *dice = card->private_data;

	snd_dice_transaction_destroy(dice);
	mutex_destroy(&dice->mutex);
}

C
Clemens Ladisch 已提交
237 238 239
static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
{
	struct snd_card *card;
240
	struct snd_dice *dice;
C
Clemens Ladisch 已提交
241 242
	int err;

243 244
	err = dice_interface_check(unit);
	if (err < 0)
245
		goto end;
246

247 248
	err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
			   sizeof(*dice), &card);
C
Clemens Ladisch 已提交
249
	if (err < 0)
250
		goto end;
C
Clemens Ladisch 已提交
251 252 253

	dice = card->private_data;
	dice->card = card;
254 255 256
	dice->unit = unit;
	card->private_free = dice_card_free;

257
	spin_lock_init(&dice->lock);
C
Clemens Ladisch 已提交
258
	mutex_init(&dice->mutex);
259
	init_completion(&dice->clock_accepted);
260
	init_waitqueue_head(&dice->hwdep_wait);
C
Clemens Ladisch 已提交
261

262
	err = snd_dice_transaction_init(dice);
C
Clemens Ladisch 已提交
263
	if (err < 0)
264
		goto error;
265 266 267

	err = dice_read_params(dice);
	if (err < 0)
268
		goto error;
C
Clemens Ladisch 已提交
269 270 271

	dice_card_strings(dice);

272
	err = snd_dice_create_pcm(dice);
C
Clemens Ladisch 已提交
273 274 275
	if (err < 0)
		goto error;

276
	err = snd_dice_create_hwdep(dice);
C
Clemens Ladisch 已提交
277 278 279
	if (err < 0)
		goto error;

280
	snd_dice_create_proc(dice);
281

282
	err = snd_dice_stream_init_duplex(dice);
C
Clemens Ladisch 已提交
283 284 285
	if (err < 0)
		goto error;

286 287
	err = snd_card_register(card);
	if (err < 0) {
288
		snd_dice_stream_destroy_duplex(dice);
289 290
		goto error;
	}
C
Clemens Ladisch 已提交
291

292 293 294
	dev_set_drvdata(&unit->device, dice);
end:
	return err;
C
Clemens Ladisch 已提交
295 296 297 298 299 300 301
error:
	snd_card_free(card);
	return err;
}

static void dice_remove(struct fw_unit *unit)
{
302
	struct snd_dice *dice = dev_get_drvdata(&unit->device);
C
Clemens Ladisch 已提交
303

304 305
	snd_card_disconnect(dice->card);

306
	snd_dice_stream_destroy_duplex(dice);
307

C
Clemens Ladisch 已提交
308 309 310 311 312
	snd_card_free_when_closed(dice->card);
}

static void dice_bus_reset(struct fw_unit *unit)
{
313
	struct snd_dice *dice = dev_get_drvdata(&unit->device);
C
Clemens Ladisch 已提交
314

315 316 317
	/* The handler address register becomes initialized. */
	snd_dice_transaction_reinit(dice);

S
Stefan Richter 已提交
318
	mutex_lock(&dice->mutex);
319
	snd_dice_stream_update_duplex(dice);
C
Clemens Ladisch 已提交
320 321 322 323 324 325 326
	mutex_unlock(&dice->mutex);
}

#define DICE_INTERFACE	0x000001

static const struct ieee1394_device_id dice_id_table[] = {
	{
327 328
		.match_flags = IEEE1394_MATCH_VERSION,
		.version     = DICE_INTERFACE,
C
Clemens Ladisch 已提交
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
	},
	{ }
};
MODULE_DEVICE_TABLE(ieee1394, dice_id_table);

static struct fw_driver dice_driver = {
	.driver   = {
		.owner	= THIS_MODULE,
		.name	= KBUILD_MODNAME,
		.bus	= &fw_bus_type,
	},
	.probe    = dice_probe,
	.update   = dice_bus_reset,
	.remove   = dice_remove,
	.id_table = dice_id_table,
};

static int __init alsa_dice_init(void)
{
	return driver_register(&dice_driver.driver);
}

static void __exit alsa_dice_exit(void)
{
	driver_unregister(&dice_driver.driver);
}

module_init(alsa_dice_init);
module_exit(alsa_dice_exit);