dice.c 8.6 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
#define OUI_WEISS		0x001c6a
15
#define OUI_LOUD		0x000ff2
16 17
#define OUI_FOCUSRITE		0x00130e
#define OUI_TCELECTRONIC	0x001486
18 19 20

#define DICE_CATEGORY_ID	0x04
#define WEISS_CATEGORY_ID	0x00
21
#define LOUD_CATEGORY_ID	0x10
22

23 24
#define PROBE_DELAY_MS		(2 * MSEC_PER_SEC)

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
/*
 * Some models support several isochronous channels, while these streams are not
 * always available. In this case, add the model name to this list.
 */
static bool force_two_pcm_support(struct fw_unit *unit)
{
	const char *const models[] = {
		/* TC Electronic models. */
		"StudioKonnekt48",
		/* Focusrite models. */
		"SAFFIRE_PRO_40",
		"LIQUID_SAFFIRE_56",
		"SAFFIRE_PRO_40_1",
	};
	char model[32];
	unsigned int i;
	int err;

	err = fw_csr_string(unit->directory, CSR_MODEL, model, sizeof(model));
	if (err < 0)
		return false;

	for (i = 0; i < ARRAY_SIZE(models); i++) {
		if (strcmp(models[i], model) == 0)
			break;
	}

	return i < ARRAY_SIZE(models);
}

55
static int check_dice_category(struct fw_unit *unit)
56 57 58
{
	struct fw_device *device = fw_parent_device(unit);
	struct fw_csr_iterator it;
59 60
	int key, val, vendor = -1, model = -1;
	unsigned int category;
61

62 63 64
	/*
	 * 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
65 66
	 * GUID chip ID consists of the 8-bit category ID, the 10-bit product
	 * ID, and a 22-bit serial number.
67 68
	 */
	fw_csr_iterator_init(&it, unit->directory);
69
	while (fw_csr_iterator_next(&it, &key, &val)) {
70 71
		switch (key) {
		case CSR_SPECIFIER_ID:
72
			vendor = val;
73 74
			break;
		case CSR_MODEL:
75
			model = val;
76 77 78
			break;
		}
	}
79 80 81 82 83 84

	if (vendor == OUI_FOCUSRITE || vendor == OUI_TCELECTRONIC) {
		if (force_two_pcm_support(unit))
			return 0;
	}

85 86
	if (vendor == OUI_WEISS)
		category = WEISS_CATEGORY_ID;
87 88
	else if (vendor == OUI_LOUD)
		category = LOUD_CATEGORY_ID;
89 90 91
	else
		category = DICE_CATEGORY_ID;
	if (device->config_rom[3] != ((vendor << 8) | category) ||
92 93
	    device->config_rom[4] >> 22 != model)
		return -ENODEV;
94

95
	return 0;
96 97
}

98
static int check_clock_caps(struct snd_dice *dice)
C
Clemens Ladisch 已提交
99
{
100
	__be32 value;
101
	int err;
C
Clemens Ladisch 已提交
102

103
	/* some very old firmwares don't tell about their clock support */
104 105 106 107
	if (dice->clock_caps > 0) {
		err = snd_dice_transaction_read_global(dice,
						GLOBAL_CLOCK_CAPABILITIES,
						&value, 4);
108 109 110 111 112 113 114 115 116 117 118
		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;
	}

C
Clemens Ladisch 已提交
119 120 121
	return 0;
}

122
static void dice_card_strings(struct snd_dice *dice)
C
Clemens Ladisch 已提交
123 124 125 126 127 128 129 130 131 132 133
{
	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));
134 135 136
	err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME,
					       card->shortname,
					       sizeof(card->shortname));
C
Clemens Ladisch 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149
	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),
150 151
		 "%s %s (serial %u) at %s, S%d",
		 vendor, model, dev->config_rom[4] & 0x3fffff,
C
Clemens Ladisch 已提交
152 153 154 155 156
		 dev_name(&dice->unit->device), 100 << dev->max_speed);

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

157 158 159 160 161 162 163 164 165 166
static void dice_free(struct snd_dice *dice)
{
	snd_dice_stream_destroy_duplex(dice);
	snd_dice_transaction_destroy(dice);
	fw_unit_put(dice->unit);

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

167 168 169 170 171 172
/*
 * This module releases the FireWire unit data after all ALSA character devices
 * are released by applications. This is for releasing stream data or finishing
 * transactions safely. Thus at returning from .remove(), this module still keep
 * references for the unit.
 */
173 174
static void dice_card_free(struct snd_card *card)
{
175
	dice_free(card->private_data);
176 177
}

178
static void do_registration(struct work_struct *work)
C
Clemens Ladisch 已提交
179
{
180
	struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work);
C
Clemens Ladisch 已提交
181 182
	int err;

183 184
	if (dice->registered)
		return;
185

186 187
	err = snd_card_new(&dice->unit->device, -1, NULL, THIS_MODULE, 0,
			   &dice->card);
C
Clemens Ladisch 已提交
188
	if (err < 0)
189
		return;
C
Clemens Ladisch 已提交
190

191 192 193
	if (force_two_pcm_support(dice->unit))
		dice->force_two_pcms = true;

194
	err = snd_dice_transaction_init(dice);
C
Clemens Ladisch 已提交
195
	if (err < 0)
196
		goto error;
197

198
	err = check_clock_caps(dice);
199
	if (err < 0)
200
		goto error;
C
Clemens Ladisch 已提交
201 202 203

	dice_card_strings(dice);

204 205
	snd_dice_create_proc(dice);

206
	err = snd_dice_create_pcm(dice);
C
Clemens Ladisch 已提交
207 208 209
	if (err < 0)
		goto error;

210
	err = snd_dice_create_midi(dice);
C
Clemens Ladisch 已提交
211 212 213
	if (err < 0)
		goto error;

214
	err = snd_dice_create_hwdep(dice);
215 216 217
	if (err < 0)
		goto error;

218
	err = snd_card_register(dice->card);
C
Clemens Ladisch 已提交
219 220 221
	if (err < 0)
		goto error;

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
	/*
	 * After registered, dice instance can be released corresponding to
	 * releasing the sound card instance.
	 */
	dice->card->private_free = dice_card_free;
	dice->card->private_data = dice;
	dice->registered = true;

	return;
error:
	snd_dice_transaction_destroy(dice);
	snd_card_free(dice->card);
	dev_info(&dice->unit->device,
		 "Sound card registration failed: %d\n", err);
}

static void schedule_registration(struct snd_dice *dice)
{
	struct fw_card *fw_card = fw_parent_device(dice->unit)->card;
	u64 now, delay;

	now = get_jiffies_64();
	delay = fw_card->reset_jiffies + msecs_to_jiffies(PROBE_DELAY_MS);

	if (time_after64(delay, now))
		delay -= now;
	else
		delay = 0;

	mod_delayed_work(system_wq, &dice->dwork, delay);
}

static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
{
	struct snd_dice *dice;
	int err;

	err = check_dice_category(unit);
	if (err < 0)
		return -ENODEV;

	/* Allocate this independent of sound card instance. */
	dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL);
	if (dice == NULL)
		return -ENOMEM;

	dice->unit = fw_unit_get(unit);
	dev_set_drvdata(&unit->device, dice);

	spin_lock_init(&dice->lock);
	mutex_init(&dice->mutex);
	init_completion(&dice->clock_accepted);
	init_waitqueue_head(&dice->hwdep_wait);

	err = snd_dice_stream_init_duplex(dice);
277
	if (err < 0) {
278 279
		dice_free(dice);
		return err;
280
	}
C
Clemens Ladisch 已提交
281

282 283 284 285 286
	/* Allocate and register this sound card later. */
	INIT_DEFERRABLE_WORK(&dice->dwork, do_registration);
	schedule_registration(dice);

	return 0;
C
Clemens Ladisch 已提交
287 288 289 290
}

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

293 294 295 296 297 298 299 300 301 302 303 304 305 306
	/*
	 * Confirm to stop the work for registration before the sound card is
	 * going to be released. The work is not scheduled again because bus
	 * reset handler is not called anymore.
	 */
	cancel_delayed_work_sync(&dice->dwork);

	if (dice->registered) {
		/* No need to wait for releasing card object in this context. */
		snd_card_free_when_closed(dice->card);
	} else {
		/* Don't forget this case. */
		dice_free(dice);
	}
C
Clemens Ladisch 已提交
307 308 309 310
}

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

313 314 315 316
	/* Postpone a workqueue for deferred registration. */
	if (!dice->registered)
		schedule_registration(dice);

317 318 319
	/* The handler address register becomes initialized. */
	snd_dice_transaction_reinit(dice);

320 321 322 323 324 325 326 327 328
	/*
	 * After registration, userspace can start packet streaming, then this
	 * code block works fine.
	 */
	if (dice->registered) {
		mutex_lock(&dice->mutex);
		snd_dice_stream_update_duplex(dice);
		mutex_unlock(&dice->mutex);
	}
C
Clemens Ladisch 已提交
329 330 331 332 333 334
}

#define DICE_INTERFACE	0x000001

static const struct ieee1394_device_id dice_id_table[] = {
	{
335 336
		.match_flags = IEEE1394_MATCH_VERSION,
		.version     = DICE_INTERFACE,
C
Clemens Ladisch 已提交
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	},
	{ }
};
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);