Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * tascam.c - a part of driver for TASCAM FireWire series
0004  *
0005  * Copyright (c) 2015 Takashi Sakamoto
0006  */
0007 
0008 #include "tascam.h"
0009 
0010 MODULE_DESCRIPTION("TASCAM FireWire series Driver");
0011 MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
0012 MODULE_LICENSE("GPL v2");
0013 
0014 static const struct snd_tscm_spec model_specs[] = {
0015     {
0016         .name = "FW-1884",
0017         .has_adat = true,
0018         .has_spdif = true,
0019         .pcm_capture_analog_channels = 8,
0020         .pcm_playback_analog_channels = 8,
0021         .midi_capture_ports = 4,
0022         .midi_playback_ports = 4,
0023     },
0024     {
0025         .name = "FW-1082",
0026         .has_adat = false,
0027         .has_spdif = true,
0028         .pcm_capture_analog_channels = 8,
0029         .pcm_playback_analog_channels = 2,
0030         .midi_capture_ports = 2,
0031         .midi_playback_ports = 2,
0032     },
0033     {
0034         .name = "FW-1804",
0035         .has_adat = true,
0036         .has_spdif = true,
0037         .pcm_capture_analog_channels = 8,
0038         .pcm_playback_analog_channels = 2,
0039         .midi_capture_ports = 2,
0040         .midi_playback_ports = 4,
0041     },
0042 };
0043 
0044 static int identify_model(struct snd_tscm *tscm)
0045 {
0046     struct fw_device *fw_dev = fw_parent_device(tscm->unit);
0047     const u32 *config_rom = fw_dev->config_rom;
0048     char model[9];
0049     unsigned int i;
0050     u8 c;
0051 
0052     if (fw_dev->config_rom_length < 30) {
0053         dev_err(&tscm->unit->device,
0054             "Configuration ROM is too short.\n");
0055         return -ENODEV;
0056     }
0057 
0058     /* Pick up model name from certain addresses. */
0059     for (i = 0; i < 8; i++) {
0060         c = config_rom[28 + i / 4] >> (24 - 8 * (i % 4));
0061         if (c == '\0')
0062             break;
0063         model[i] = c;
0064     }
0065     model[i] = '\0';
0066 
0067     for (i = 0; i < ARRAY_SIZE(model_specs); i++) {
0068         if (strcmp(model, model_specs[i].name) == 0) {
0069             tscm->spec = &model_specs[i];
0070             break;
0071         }
0072     }
0073     if (tscm->spec == NULL)
0074         return -ENODEV;
0075 
0076     strcpy(tscm->card->driver, "FW-TASCAM");
0077     strcpy(tscm->card->shortname, model);
0078     strcpy(tscm->card->mixername, model);
0079     snprintf(tscm->card->longname, sizeof(tscm->card->longname),
0080          "TASCAM %s, GUID %08x%08x at %s, S%d", model,
0081          fw_dev->config_rom[3], fw_dev->config_rom[4],
0082          dev_name(&tscm->unit->device), 100 << fw_dev->max_speed);
0083 
0084     return 0;
0085 }
0086 
0087 static void tscm_card_free(struct snd_card *card)
0088 {
0089     struct snd_tscm *tscm = card->private_data;
0090 
0091     snd_tscm_transaction_unregister(tscm);
0092     snd_tscm_stream_destroy_duplex(tscm);
0093 
0094     mutex_destroy(&tscm->mutex);
0095     fw_unit_put(tscm->unit);
0096 }
0097 
0098 static int snd_tscm_probe(struct fw_unit *unit,
0099                const struct ieee1394_device_id *entry)
0100 {
0101     struct snd_card *card;
0102     struct snd_tscm *tscm;
0103     int err;
0104 
0105     err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*tscm), &card);
0106     if (err < 0)
0107         return err;
0108     card->private_free = tscm_card_free;
0109 
0110     tscm = card->private_data;
0111     tscm->unit = fw_unit_get(unit);
0112     dev_set_drvdata(&unit->device, tscm);
0113     tscm->card = card;
0114 
0115     mutex_init(&tscm->mutex);
0116     spin_lock_init(&tscm->lock);
0117     init_waitqueue_head(&tscm->hwdep_wait);
0118 
0119     err = identify_model(tscm);
0120     if (err < 0)
0121         goto error;
0122 
0123     err = snd_tscm_transaction_register(tscm);
0124     if (err < 0)
0125         goto error;
0126 
0127     err = snd_tscm_stream_init_duplex(tscm);
0128     if (err < 0)
0129         goto error;
0130 
0131     snd_tscm_proc_init(tscm);
0132 
0133     err = snd_tscm_create_pcm_devices(tscm);
0134     if (err < 0)
0135         goto error;
0136 
0137     err = snd_tscm_create_midi_devices(tscm);
0138     if (err < 0)
0139         goto error;
0140 
0141     err = snd_tscm_create_hwdep_device(tscm);
0142     if (err < 0)
0143         goto error;
0144 
0145     err = snd_card_register(card);
0146     if (err < 0)
0147         goto error;
0148 
0149     return 0;
0150 error:
0151     snd_card_free(card);
0152     return err;
0153 }
0154 
0155 static void snd_tscm_update(struct fw_unit *unit)
0156 {
0157     struct snd_tscm *tscm = dev_get_drvdata(&unit->device);
0158 
0159     snd_tscm_transaction_reregister(tscm);
0160 
0161     mutex_lock(&tscm->mutex);
0162     snd_tscm_stream_update_duplex(tscm);
0163     mutex_unlock(&tscm->mutex);
0164 }
0165 
0166 static void snd_tscm_remove(struct fw_unit *unit)
0167 {
0168     struct snd_tscm *tscm = dev_get_drvdata(&unit->device);
0169 
0170     // Block till all of ALSA character devices are released.
0171     snd_card_free(tscm->card);
0172 }
0173 
0174 static const struct ieee1394_device_id snd_tscm_id_table[] = {
0175     // Tascam, FW-1884.
0176     {
0177         .match_flags = IEEE1394_MATCH_VENDOR_ID |
0178                    IEEE1394_MATCH_SPECIFIER_ID |
0179                    IEEE1394_MATCH_VERSION,
0180         .vendor_id = 0x00022e,
0181         .specifier_id = 0x00022e,
0182         .version = 0x800000,
0183     },
0184     // Tascam, FE-8 (.version = 0x800001)
0185     // This kernel module doesn't support FE-8 because the most of features
0186     // can be implemented in userspace without any specific support of this
0187     // module.
0188     //
0189     // .version = 0x800002 is unknown.
0190     //
0191     // Tascam, FW-1082.
0192     {
0193         .match_flags = IEEE1394_MATCH_VENDOR_ID |
0194                    IEEE1394_MATCH_SPECIFIER_ID |
0195                    IEEE1394_MATCH_VERSION,
0196         .vendor_id = 0x00022e,
0197         .specifier_id = 0x00022e,
0198         .version = 0x800003,
0199     },
0200     // Tascam, FW-1804.
0201     {
0202         .match_flags = IEEE1394_MATCH_VENDOR_ID |
0203                    IEEE1394_MATCH_SPECIFIER_ID |
0204                    IEEE1394_MATCH_VERSION,
0205         .vendor_id = 0x00022e,
0206         .specifier_id = 0x00022e,
0207         .version = 0x800004,
0208     },
0209     {}
0210 };
0211 MODULE_DEVICE_TABLE(ieee1394, snd_tscm_id_table);
0212 
0213 static struct fw_driver tscm_driver = {
0214     .driver = {
0215         .owner = THIS_MODULE,
0216         .name = KBUILD_MODNAME,
0217         .bus = &fw_bus_type,
0218     },
0219     .probe    = snd_tscm_probe,
0220     .update   = snd_tscm_update,
0221     .remove   = snd_tscm_remove,
0222     .id_table = snd_tscm_id_table,
0223 };
0224 
0225 static int __init snd_tscm_init(void)
0226 {
0227     return driver_register(&tscm_driver.driver);
0228 }
0229 
0230 static void __exit snd_tscm_exit(void)
0231 {
0232     driver_unregister(&tscm_driver.driver);
0233 }
0234 
0235 module_init(snd_tscm_init);
0236 module_exit(snd_tscm_exit);