linux/sound/firewire/motu/motu.c
<<
>>
Prefs
   1/*
   2 * motu.c - a part of driver for MOTU FireWire series
   3 *
   4 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
   5 *
   6 * Licensed under the terms of the GNU General Public License, version 2.
   7 */
   8
   9#include "motu.h"
  10
  11#define OUI_MOTU        0x0001f2
  12
  13MODULE_DESCRIPTION("MOTU FireWire driver");
  14MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
  15MODULE_LICENSE("GPL v2");
  16
  17const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT] = {
  18        /* mode 0 */
  19        [0] =  44100,
  20        [1] =  48000,
  21        /* mode 1 */
  22        [2] =  88200,
  23        [3] =  96000,
  24        /* mode 2 */
  25        [4] = 176400,
  26        [5] = 192000,
  27};
  28
  29static void name_card(struct snd_motu *motu)
  30{
  31        struct fw_device *fw_dev = fw_parent_device(motu->unit);
  32        struct fw_csr_iterator it;
  33        int key, val;
  34        u32 version = 0;
  35
  36        fw_csr_iterator_init(&it, motu->unit->directory);
  37        while (fw_csr_iterator_next(&it, &key, &val)) {
  38                switch (key) {
  39                case CSR_VERSION:
  40                        version = val;
  41                        break;
  42                }
  43        }
  44
  45        strcpy(motu->card->driver, "FW-MOTU");
  46        strcpy(motu->card->shortname, motu->spec->name);
  47        strcpy(motu->card->mixername, motu->spec->name);
  48        snprintf(motu->card->longname, sizeof(motu->card->longname),
  49                 "MOTU %s (version:%d), GUID %08x%08x at %s, S%d",
  50                 motu->spec->name, version,
  51                 fw_dev->config_rom[3], fw_dev->config_rom[4],
  52                 dev_name(&motu->unit->device), 100 << fw_dev->max_speed);
  53}
  54
  55static void motu_free(struct snd_motu *motu)
  56{
  57        snd_motu_transaction_unregister(motu);
  58
  59        snd_motu_stream_destroy_duplex(motu);
  60        fw_unit_put(motu->unit);
  61
  62        mutex_destroy(&motu->mutex);
  63        kfree(motu);
  64}
  65
  66/*
  67 * This module releases the FireWire unit data after all ALSA character devices
  68 * are released by applications. This is for releasing stream data or finishing
  69 * transactions safely. Thus at returning from .remove(), this module still keep
  70 * references for the unit.
  71 */
  72static void motu_card_free(struct snd_card *card)
  73{
  74        motu_free(card->private_data);
  75}
  76
  77static void do_registration(struct work_struct *work)
  78{
  79        struct snd_motu *motu = container_of(work, struct snd_motu, dwork.work);
  80        int err;
  81
  82        if (motu->registered)
  83                return;
  84
  85        err = snd_card_new(&motu->unit->device, -1, NULL, THIS_MODULE, 0,
  86                           &motu->card);
  87        if (err < 0)
  88                return;
  89
  90        name_card(motu);
  91
  92        err = snd_motu_transaction_register(motu);
  93        if (err < 0)
  94                goto error;
  95
  96        err = snd_motu_stream_init_duplex(motu);
  97        if (err < 0)
  98                goto error;
  99
 100        snd_motu_proc_init(motu);
 101
 102        err = snd_motu_create_pcm_devices(motu);
 103        if (err < 0)
 104                goto error;
 105
 106        if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
 107            (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) ||
 108            (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
 109            (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q)) {
 110                err = snd_motu_create_midi_devices(motu);
 111                if (err < 0)
 112                        goto error;
 113        }
 114
 115        err = snd_motu_create_hwdep_device(motu);
 116        if (err < 0)
 117                goto error;
 118
 119        err = snd_card_register(motu->card);
 120        if (err < 0)
 121                goto error;
 122
 123        /*
 124         * After registered, motu instance can be released corresponding to
 125         * releasing the sound card instance.
 126         */
 127        motu->card->private_free = motu_card_free;
 128        motu->card->private_data = motu;
 129        motu->registered = true;
 130
 131        return;
 132error:
 133        snd_motu_transaction_unregister(motu);
 134        snd_motu_stream_destroy_duplex(motu);
 135        snd_card_free(motu->card);
 136        dev_info(&motu->unit->device,
 137                 "Sound card registration failed: %d\n", err);
 138}
 139
 140static int motu_probe(struct fw_unit *unit,
 141                      const struct ieee1394_device_id *entry)
 142{
 143        struct snd_motu *motu;
 144
 145        /* Allocate this independently of sound card instance. */
 146        motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL);
 147        if (motu == NULL)
 148                return -ENOMEM;
 149
 150        motu->spec = (const struct snd_motu_spec *)entry->driver_data;
 151        motu->unit = fw_unit_get(unit);
 152        dev_set_drvdata(&unit->device, motu);
 153
 154        mutex_init(&motu->mutex);
 155        spin_lock_init(&motu->lock);
 156        init_waitqueue_head(&motu->hwdep_wait);
 157
 158        /* Allocate and register this sound card later. */
 159        INIT_DEFERRABLE_WORK(&motu->dwork, do_registration);
 160        snd_fw_schedule_registration(unit, &motu->dwork);
 161
 162        return 0;
 163}
 164
 165static void motu_remove(struct fw_unit *unit)
 166{
 167        struct snd_motu *motu = dev_get_drvdata(&unit->device);
 168
 169        /*
 170         * Confirm to stop the work for registration before the sound card is
 171         * going to be released. The work is not scheduled again because bus
 172         * reset handler is not called anymore.
 173         */
 174        cancel_delayed_work_sync(&motu->dwork);
 175
 176        if (motu->registered) {
 177                /* No need to wait for releasing card object in this context. */
 178                snd_card_free_when_closed(motu->card);
 179        } else {
 180                /* Don't forget this case. */
 181                motu_free(motu);
 182        }
 183}
 184
 185static void motu_bus_update(struct fw_unit *unit)
 186{
 187        struct snd_motu *motu = dev_get_drvdata(&unit->device);
 188
 189        /* Postpone a workqueue for deferred registration. */
 190        if (!motu->registered)
 191                snd_fw_schedule_registration(unit, &motu->dwork);
 192
 193        /* The handler address register becomes initialized. */
 194        snd_motu_transaction_reregister(motu);
 195}
 196
 197static const struct snd_motu_spec motu_828mk2 = {
 198        .name = "828mk2",
 199        .protocol = &snd_motu_protocol_v2,
 200        .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
 201                 SND_MOTU_SPEC_TX_MICINST_CHUNK |
 202                 SND_MOTU_SPEC_TX_RETURN_CHUNK |
 203                 SND_MOTU_SPEC_HAS_OPT_IFACE_A |
 204                 SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 205                 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
 206
 207        .analog_in_ports = 8,
 208        .analog_out_ports = 8,
 209};
 210
 211static const struct snd_motu_spec motu_828mk3 = {
 212        .name = "828mk3",
 213        .protocol = &snd_motu_protocol_v3,
 214        .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
 215                 SND_MOTU_SPEC_SUPPORT_CLOCK_X4 |
 216                 SND_MOTU_SPEC_TX_MICINST_CHUNK |
 217                 SND_MOTU_SPEC_TX_RETURN_CHUNK |
 218                 SND_MOTU_SPEC_TX_REVERB_CHUNK |
 219                 SND_MOTU_SPEC_HAS_OPT_IFACE_A |
 220                 SND_MOTU_SPEC_HAS_OPT_IFACE_B |
 221                 SND_MOTU_SPEC_RX_MIDI_3RD_Q |
 222                 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
 223
 224        .analog_in_ports = 8,
 225        .analog_out_ports = 8,
 226};
 227
 228static const struct snd_motu_spec motu_audio_express = {
 229        .name = "AudioExpress",
 230        .protocol = &snd_motu_protocol_v3,
 231        .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
 232                 SND_MOTU_SPEC_TX_MICINST_CHUNK |
 233                 SND_MOTU_SPEC_TX_RETURN_CHUNK |
 234                 SND_MOTU_SPEC_RX_MIDI_2ND_Q |
 235                 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
 236        .analog_in_ports = 2,
 237        .analog_out_ports = 4,
 238};
 239
 240#define SND_MOTU_DEV_ENTRY(model, data)                 \
 241{                                                       \
 242        .match_flags    = IEEE1394_MATCH_VENDOR_ID |    \
 243                          IEEE1394_MATCH_MODEL_ID |     \
 244                          IEEE1394_MATCH_SPECIFIER_ID,  \
 245        .vendor_id      = OUI_MOTU,                     \
 246        .model_id       = model,                        \
 247        .specifier_id   = OUI_MOTU,                     \
 248        .driver_data    = (kernel_ulong_t)data,         \
 249}
 250
 251static const struct ieee1394_device_id motu_id_table[] = {
 252        SND_MOTU_DEV_ENTRY(0x101800, &motu_828mk2),
 253        SND_MOTU_DEV_ENTRY(0x106800, &motu_828mk3),     /* FireWire only. */
 254        SND_MOTU_DEV_ENTRY(0x100800, &motu_828mk3),     /* Hybrid. */
 255        SND_MOTU_DEV_ENTRY(0x104800, &motu_audio_express),
 256        { }
 257};
 258MODULE_DEVICE_TABLE(ieee1394, motu_id_table);
 259
 260static struct fw_driver motu_driver = {
 261        .driver   = {
 262                .owner  = THIS_MODULE,
 263                .name   = KBUILD_MODNAME,
 264                .bus    = &fw_bus_type,
 265        },
 266        .probe    = motu_probe,
 267        .update   = motu_bus_update,
 268        .remove   = motu_remove,
 269        .id_table = motu_id_table,
 270};
 271
 272static int __init alsa_motu_init(void)
 273{
 274        return driver_register(&motu_driver.driver);
 275}
 276
 277static void __exit alsa_motu_exit(void)
 278{
 279        driver_unregister(&motu_driver.driver);
 280}
 281
 282module_init(alsa_motu_init);
 283module_exit(alsa_motu_exit);
 284