motu.c 5.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * motu.c - a part of driver for MOTU FireWire series
 *
 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
 *
 * Licensed under the terms of the GNU General Public License, version 2.
 */

#include "motu.h"

#define OUI_MOTU	0x0001f2

MODULE_DESCRIPTION("MOTU FireWire driver");
MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
MODULE_LICENSE("GPL v2");

17 18 19 20 21 22 23 24 25 26 27 28
const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT] = {
	/* mode 0 */
	[0] =  44100,
	[1] =  48000,
	/* mode 1 */
	[2] =  88200,
	[3] =  96000,
	/* mode 2 */
	[4] = 176400,
	[5] = 192000,
};

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
static void name_card(struct snd_motu *motu)
{
	struct fw_device *fw_dev = fw_parent_device(motu->unit);
	struct fw_csr_iterator it;
	int key, val;
	u32 version = 0;

	fw_csr_iterator_init(&it, motu->unit->directory);
	while (fw_csr_iterator_next(&it, &key, &val)) {
		switch (key) {
		case CSR_VERSION:
			version = val;
			break;
		}
	}

	strcpy(motu->card->driver, "FW-MOTU");
46 47
	strcpy(motu->card->shortname, motu->spec->name);
	strcpy(motu->card->mixername, motu->spec->name);
48
	snprintf(motu->card->longname, sizeof(motu->card->longname),
49 50
		 "MOTU %s (version:%d), GUID %08x%08x at %s, S%d",
		 motu->spec->name, version,
51 52 53 54
		 fw_dev->config_rom[3], fw_dev->config_rom[4],
		 dev_name(&motu->unit->device), 100 << fw_dev->max_speed);
}

55
static void motu_free(struct snd_motu *motu)
56
{
57 58
	snd_motu_transaction_unregister(motu);

59
	snd_motu_stream_destroy_duplex(motu);
60 61 62
	fw_unit_put(motu->unit);

	mutex_destroy(&motu->mutex);
63
	kfree(motu);
64 65
}

66 67 68 69 70 71 72
/*
 * 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.
 */
static void motu_card_free(struct snd_card *card)
73
{
74 75
	motu_free(card->private_data);
}
76

77 78 79 80
static void do_registration(struct work_struct *work)
{
	struct snd_motu *motu = container_of(work, struct snd_motu, dwork.work);
	int err;
81

82 83
	if (motu->registered)
		return;
84

85 86 87 88
	err = snd_card_new(&motu->unit->device, -1, NULL, THIS_MODULE, 0,
			   &motu->card);
	if (err < 0)
		return;
89 90 91

	name_card(motu);

92 93 94 95
	err = snd_motu_transaction_register(motu);
	if (err < 0)
		goto error;

96 97 98 99
	err = snd_motu_stream_init_duplex(motu);
	if (err < 0)
		goto error;

100 101
	snd_motu_proc_init(motu);

102 103 104 105
	err = snd_motu_create_pcm_devices(motu);
	if (err < 0)
		goto error;

106 107 108 109 110 111
	if (motu->spec->flags & SND_MOTU_SPEC_HAS_MIDI) {
		err = snd_motu_create_midi_devices(motu);
		if (err < 0)
			goto error;
	}

112 113 114 115
	err = snd_motu_create_hwdep_device(motu);
	if (err < 0)
		goto error;

116
	err = snd_card_register(motu->card);
117 118 119
	if (err < 0)
		goto error;

120 121 122 123 124 125 126 127 128 129
	/*
	 * After registered, motu instance can be released corresponding to
	 * releasing the sound card instance.
	 */
	motu->card->private_free = motu_card_free;
	motu->card->private_data = motu;
	motu->registered = true;

	return;
error:
130
	snd_motu_transaction_unregister(motu);
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	snd_card_free(motu->card);
	dev_info(&motu->unit->device,
		 "Sound card registration failed: %d\n", err);
}

static int motu_probe(struct fw_unit *unit,
		      const struct ieee1394_device_id *entry)
{
	struct snd_motu *motu;

	/* Allocate this independently of sound card instance. */
	motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL);
	if (motu == NULL)
		return -ENOMEM;

146
	motu->spec = (const struct snd_motu_spec *)entry->driver_data;
147
	motu->unit = fw_unit_get(unit);
148 149
	dev_set_drvdata(&unit->device, motu);

150
	mutex_init(&motu->mutex);
151
	spin_lock_init(&motu->lock);
152
	init_waitqueue_head(&motu->hwdep_wait);
153 154 155 156 157

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

158 159 160 161 162 163 164
	return 0;
}

static void motu_remove(struct fw_unit *unit)
{
	struct snd_motu *motu = dev_get_drvdata(&unit->device);

165 166 167 168 169 170 171 172 173 174 175 176 177 178
	/*
	 * 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(&motu->dwork);

	if (motu->registered) {
		/* No need to wait for releasing card object in this context. */
		snd_card_free_when_closed(motu->card);
	} else {
		/* Don't forget this case. */
		motu_free(motu);
	}
179 180 181 182
}

static void motu_bus_update(struct fw_unit *unit)
{
183 184 185 186 187
	struct snd_motu *motu = dev_get_drvdata(&unit->device);

	/* Postpone a workqueue for deferred registration. */
	if (!motu->registered)
		snd_fw_schedule_registration(unit, &motu->dwork);
188 189 190

	/* The handler address register becomes initialized. */
	snd_motu_transaction_reregister(motu);
191 192
}

193
#define SND_MOTU_DEV_ENTRY(model, data)			\
194 195 196 197 198 199 200
{							\
	.match_flags	= IEEE1394_MATCH_VENDOR_ID |	\
			  IEEE1394_MATCH_MODEL_ID |	\
			  IEEE1394_MATCH_SPECIFIER_ID,	\
	.vendor_id	= OUI_MOTU,			\
	.model_id	= model,			\
	.specifier_id	= OUI_MOTU,			\
201
	.driver_data	= (kernel_ulong_t)data,		\
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
}

static const struct ieee1394_device_id motu_id_table[] = {
	{ }
};
MODULE_DEVICE_TABLE(ieee1394, motu_id_table);

static struct fw_driver motu_driver = {
	.driver   = {
		.owner	= THIS_MODULE,
		.name	= KBUILD_MODNAME,
		.bus	= &fw_bus_type,
	},
	.probe    = motu_probe,
	.update   = motu_bus_update,
	.remove   = motu_remove,
	.id_table = motu_id_table,
};

static int __init alsa_motu_init(void)
{
	return driver_register(&motu_driver.driver);
}

static void __exit alsa_motu_exit(void)
{
	driver_unregister(&motu_driver.driver);
}

module_init(alsa_motu_init);
module_exit(alsa_motu_exit);