11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Dummy soundcard for virtual rawmidi devices 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 2000 by Takashi Iwai <tiwai@suse.de> 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds /* 91da177e4SLinus Torvalds * VIRTUAL RAW MIDI DEVICE CARDS 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This dummy card contains up to 4 virtual rawmidi devices. 121da177e4SLinus Torvalds * They are not real rawmidi devices but just associated with sequencer 131da177e4SLinus Torvalds * clients, so that any input/output sources can be connected as a raw 141da177e4SLinus Torvalds * MIDI device arbitrary. 151da177e4SLinus Torvalds * Also, multiple access is allowed to a single rawmidi device. 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * Typical usage is like following: 181da177e4SLinus Torvalds * - Load snd-virmidi module. 191da177e4SLinus Torvalds * # modprobe snd-virmidi index=2 201da177e4SLinus Torvalds * Then, sequencer clients 72:0 to 75:0 will be created, which are 211da177e4SLinus Torvalds * mapped from /dev/snd/midiC1D0 to /dev/snd/midiC1D3, respectively. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * - Connect input/output via aconnect. 241da177e4SLinus Torvalds * % aconnect 64:0 72:0 # keyboard input redirection 64:0 -> 72:0 251da177e4SLinus Torvalds * % aconnect 72:0 65:0 # output device redirection 72:0 -> 65:0 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * - Run application using a midi device (eg. /dev/snd/midiC1D0) 281da177e4SLinus Torvalds */ 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #include <linux/init.h> 311da177e4SLinus Torvalds #include <linux/wait.h> 323564fbb8STakashi Iwai #include <linux/err.h> 333564fbb8STakashi Iwai #include <linux/platform_device.h> 3465a77217SPaul Gortmaker #include <linux/module.h> 351da177e4SLinus Torvalds #include <sound/core.h> 361da177e4SLinus Torvalds #include <sound/seq_kernel.h> 371da177e4SLinus Torvalds #include <sound/seq_virmidi.h> 381da177e4SLinus Torvalds #include <sound/initval.h> 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds /* hack: OSS defines midi_devs, so undefine it (versioned symbols) */ 411da177e4SLinus Torvalds #undef midi_devs 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 441da177e4SLinus Torvalds MODULE_DESCRIPTION("Dummy soundcard for virtual rawmidi devices"); 451da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 461da177e4SLinus Torvalds 47204bdb1bSClemens Ladisch #define MAX_MIDI_DEVICES 4 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 501da177e4SLinus Torvalds static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 51a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; 521da177e4SLinus Torvalds static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds module_param_array(index, int, NULL, 0444); 551da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for virmidi soundcard."); 561da177e4SLinus Torvalds module_param_array(id, charp, NULL, 0444); 571da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for virmidi soundcard."); 581da177e4SLinus Torvalds module_param_array(enable, bool, NULL, 0444); 591da177e4SLinus Torvalds MODULE_PARM_DESC(enable, "Enable this soundcard."); 601da177e4SLinus Torvalds module_param_array(midi_devs, int, NULL, 0444); 61204bdb1bSClemens Ladisch MODULE_PARM_DESC(midi_devs, "MIDI devices # (1-4)"); 621da177e4SLinus Torvalds 634a4d2cfdSTakashi Iwai struct snd_card_virmidi { 644a4d2cfdSTakashi Iwai struct snd_card *card; 654a4d2cfdSTakashi Iwai struct snd_rawmidi *midi[MAX_MIDI_DEVICES]; 664a4d2cfdSTakashi Iwai }; 671da177e4SLinus Torvalds 68f7a9275dSClemens Ladisch static struct platform_device *devices[SNDRV_CARDS]; 69f7a9275dSClemens Ladisch 701da177e4SLinus Torvalds 71fbbb01a1SBill Pemberton static int snd_virmidi_probe(struct platform_device *devptr) 721da177e4SLinus Torvalds { 734a4d2cfdSTakashi Iwai struct snd_card *card; 741da177e4SLinus Torvalds struct snd_card_virmidi *vmidi; 751da177e4SLinus Torvalds int idx, err; 763564fbb8STakashi Iwai int dev = devptr->id; 771da177e4SLinus Torvalds 78ed539fc3STakashi Iwai err = snd_devm_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE, 79bd7dd77cSTakashi Iwai sizeof(struct snd_card_virmidi), &card); 80bd7dd77cSTakashi Iwai if (err < 0) 81bd7dd77cSTakashi Iwai return err; 829fe856e4SJoe Perches vmidi = card->private_data; 831da177e4SLinus Torvalds vmidi->card = card; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds if (midi_devs[dev] > MAX_MIDI_DEVICES) { 86*b5557ef9STakashi Iwai dev_warn(&devptr->dev, 87316638a5SKyle Chamberlin "too much midi devices for virmidi %d: force to use %d\n", 88316638a5SKyle Chamberlin dev, MAX_MIDI_DEVICES); 891da177e4SLinus Torvalds midi_devs[dev] = MAX_MIDI_DEVICES; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds for (idx = 0; idx < midi_devs[dev]; idx++) { 924a4d2cfdSTakashi Iwai struct snd_rawmidi *rmidi; 93316638a5SKyle Chamberlin 94316638a5SKyle Chamberlin err = snd_virmidi_new(card, idx, &rmidi); 95316638a5SKyle Chamberlin if (err < 0) 96ed539fc3STakashi Iwai return err; 971da177e4SLinus Torvalds vmidi->midi[idx] = rmidi; 981da177e4SLinus Torvalds strcpy(rmidi->name, "Virtual Raw MIDI"); 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds strcpy(card->driver, "VirMIDI"); 1021da177e4SLinus Torvalds strcpy(card->shortname, "VirMIDI"); 1031da177e4SLinus Torvalds sprintf(card->longname, "Virtual MIDI Card %i", dev + 1); 10416dab54bSTakashi Iwai 105316638a5SKyle Chamberlin err = snd_card_register(card); 106ed539fc3STakashi Iwai if (err) 1071da177e4SLinus Torvalds return err; 1081da177e4SLinus Torvalds 109ed539fc3STakashi Iwai platform_set_drvdata(devptr, card); 1103564fbb8STakashi Iwai return 0; 1113564fbb8STakashi Iwai } 1123564fbb8STakashi Iwai 1133564fbb8STakashi Iwai #define SND_VIRMIDI_DRIVER "snd_virmidi" 1143564fbb8STakashi Iwai 1153564fbb8STakashi Iwai static struct platform_driver snd_virmidi_driver = { 1163564fbb8STakashi Iwai .probe = snd_virmidi_probe, 1173564fbb8STakashi Iwai .driver = { 1188bf01d8aSTakashi Iwai .name = SND_VIRMIDI_DRIVER, 1193564fbb8STakashi Iwai }, 1203564fbb8STakashi Iwai }; 1213564fbb8STakashi Iwai 122bdec0c72SRandy Dunlap static void snd_virmidi_unregister_all(void) 123f7a9275dSClemens Ladisch { 124f7a9275dSClemens Ladisch int i; 125f7a9275dSClemens Ladisch 126f7a9275dSClemens Ladisch for (i = 0; i < ARRAY_SIZE(devices); ++i) 127f7a9275dSClemens Ladisch platform_device_unregister(devices[i]); 128f7a9275dSClemens Ladisch platform_driver_unregister(&snd_virmidi_driver); 129f7a9275dSClemens Ladisch } 130f7a9275dSClemens Ladisch 1311da177e4SLinus Torvalds static int __init alsa_card_virmidi_init(void) 1321da177e4SLinus Torvalds { 1333564fbb8STakashi Iwai int i, cards, err; 1341da177e4SLinus Torvalds 135316638a5SKyle Chamberlin err = platform_driver_register(&snd_virmidi_driver); 136316638a5SKyle Chamberlin if (err < 0) 1373564fbb8STakashi Iwai return err; 1383564fbb8STakashi Iwai 1393564fbb8STakashi Iwai cards = 0; 1408278ca8fSTakashi Iwai for (i = 0; i < SNDRV_CARDS; i++) { 1413564fbb8STakashi Iwai struct platform_device *device; 142316638a5SKyle Chamberlin 1438278ca8fSTakashi Iwai if (!enable[i]) 1448278ca8fSTakashi Iwai continue; 1453564fbb8STakashi Iwai device = platform_device_register_simple(SND_VIRMIDI_DRIVER, 1463564fbb8STakashi Iwai i, NULL, 0); 147a182ee98SRene Herman if (IS_ERR(device)) 148a182ee98SRene Herman continue; 1497152447dSRene Herman if (!platform_get_drvdata(device)) { 1507152447dSRene Herman platform_device_unregister(device); 1517152447dSRene Herman continue; 1527152447dSRene Herman } 153f7a9275dSClemens Ladisch devices[i] = device; 1541da177e4SLinus Torvalds cards++; 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds if (!cards) { 1571da177e4SLinus Torvalds #ifdef MODULE 158*b5557ef9STakashi Iwai pr_err("Card-VirMIDI soundcard not found or device busy\n"); 1591da177e4SLinus Torvalds #endif 160a182ee98SRene Herman snd_virmidi_unregister_all(); 161a182ee98SRene Herman return -ENODEV; 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds return 0; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds static void __exit alsa_card_virmidi_exit(void) 1671da177e4SLinus Torvalds { 168f7a9275dSClemens Ladisch snd_virmidi_unregister_all(); 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds module_init(alsa_card_virmidi_init) 1721da177e4SLinus Torvalds module_exit(alsa_card_virmidi_exit) 173