dice.c 8.5 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 25 26 27 28
/*
 * 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)
{
29
	static const char *const models[] = {
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
		/* 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);
}

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

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

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

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

93
	return 0;
94 95
}

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

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

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

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

155 156 157 158 159 160 161 162 163 164
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);
}

165 166 167 168 169 170
/*
 * 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.
 */
171 172
static void dice_card_free(struct snd_card *card)
{
173
	dice_free(card->private_data);
174 175
}

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

181 182
	if (dice->registered)
		return;
183

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

189 190 191
	if (force_two_pcm_support(dice->unit))
		dice->force_two_pcms = true;

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

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

	dice_card_strings(dice);

202 203 204 205
	err = snd_dice_stream_init_duplex(dice);
	if (err < 0)
		goto error;

206 207
	snd_dice_create_proc(dice);

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

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

216
	err = snd_dice_create_hwdep(dice);
217 218 219
	if (err < 0)
		goto error;

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

224 225 226 227 228 229 230 231 232 233
	/*
	 * 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:
234
	snd_dice_stream_destroy_duplex(dice);
235
	snd_dice_transaction_destroy(dice);
236
	snd_dice_stream_destroy_duplex(dice);
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
	snd_card_free(dice->card);
	dev_info(&dice->unit->device,
		 "Sound card registration failed: %d\n", err);
}

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);

	/* Allocate and register this sound card later. */
	INIT_DEFERRABLE_WORK(&dice->dwork, do_registration);
266
	snd_fw_schedule_registration(unit, &dice->dwork);
267 268

	return 0;
C
Clemens Ladisch 已提交
269 270 271 272
}

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

275 276 277 278 279 280 281 282 283 284 285 286 287 288
	/*
	 * 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 已提交
289 290 291 292
}

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

295 296
	/* Postpone a workqueue for deferred registration. */
	if (!dice->registered)
297
		snd_fw_schedule_registration(unit, &dice->dwork);
298

299 300 301
	/* The handler address register becomes initialized. */
	snd_dice_transaction_reinit(dice);

302 303 304 305 306 307 308 309 310
	/*
	 * 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 已提交
311 312 313 314 315 316
}

#define DICE_INTERFACE	0x000001

static const struct ieee1394_device_id dice_id_table[] = {
	{
317 318
		.match_flags = IEEE1394_MATCH_VERSION,
		.version     = DICE_INTERFACE,
C
Clemens Ladisch 已提交
319
	},
320 321 322 323 324 325 326
	/* M-Audio Profire 610/2626 has a different value in version field. */
	{
		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
				  IEEE1394_MATCH_SPECIFIER_ID,
		.vendor_id	= 0x000d6c,
		.specifier_id	= 0x000d6c,
	},
C
Clemens Ladisch 已提交
327 328 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
	{ }
};
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);