11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Dummy soundcard for virtual rawmidi devices 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2000 by Takashi Iwai <tiwai@suse.de> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 81da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 91da177e4SLinus Torvalds * (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4SLinus Torvalds * GNU General Public License for more details. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 171da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds /* 231da177e4SLinus Torvalds * VIRTUAL RAW MIDI DEVICE CARDS 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds * This dummy card contains up to 4 virtual rawmidi devices. 261da177e4SLinus Torvalds * They are not real rawmidi devices but just associated with sequencer 271da177e4SLinus Torvalds * clients, so that any input/output sources can be connected as a raw 281da177e4SLinus Torvalds * MIDI device arbitrary. 291da177e4SLinus Torvalds * Also, multiple access is allowed to a single rawmidi device. 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds * Typical usage is like following: 321da177e4SLinus Torvalds * - Load snd-virmidi module. 331da177e4SLinus Torvalds * # modprobe snd-virmidi index=2 341da177e4SLinus Torvalds * Then, sequencer clients 72:0 to 75:0 will be created, which are 351da177e4SLinus Torvalds * mapped from /dev/snd/midiC1D0 to /dev/snd/midiC1D3, respectively. 361da177e4SLinus Torvalds * 371da177e4SLinus Torvalds * - Connect input/output via aconnect. 381da177e4SLinus Torvalds * % aconnect 64:0 72:0 # keyboard input redirection 64:0 -> 72:0 391da177e4SLinus Torvalds * % aconnect 72:0 65:0 # output device redirection 72:0 -> 65:0 401da177e4SLinus Torvalds * 411da177e4SLinus Torvalds * - Run application using a midi device (eg. /dev/snd/midiC1D0) 421da177e4SLinus Torvalds */ 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #include <linux/init.h> 451da177e4SLinus Torvalds #include <linux/wait.h> 463564fbb8STakashi Iwai #include <linux/err.h> 473564fbb8STakashi Iwai #include <linux/platform_device.h> 4865a77217SPaul Gortmaker #include <linux/module.h> 491da177e4SLinus Torvalds #include <sound/core.h> 501da177e4SLinus Torvalds #include <sound/seq_kernel.h> 511da177e4SLinus Torvalds #include <sound/seq_virmidi.h> 521da177e4SLinus Torvalds #include <sound/initval.h> 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /* hack: OSS defines midi_devs, so undefine it (versioned symbols) */ 551da177e4SLinus Torvalds #undef midi_devs 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 581da177e4SLinus Torvalds MODULE_DESCRIPTION("Dummy soundcard for virtual rawmidi devices"); 591da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 601da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("{{ALSA,Virtual rawmidi device}}"); 611da177e4SLinus Torvalds 62204bdb1bSClemens Ladisch #define MAX_MIDI_DEVICES 4 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 651da177e4SLinus Torvalds static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 66a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; 671da177e4SLinus Torvalds static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds module_param_array(index, int, NULL, 0444); 701da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for virmidi soundcard."); 711da177e4SLinus Torvalds module_param_array(id, charp, NULL, 0444); 721da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for virmidi soundcard."); 731da177e4SLinus Torvalds module_param_array(enable, bool, NULL, 0444); 741da177e4SLinus Torvalds MODULE_PARM_DESC(enable, "Enable this soundcard."); 751da177e4SLinus Torvalds module_param_array(midi_devs, int, NULL, 0444); 76204bdb1bSClemens Ladisch MODULE_PARM_DESC(midi_devs, "MIDI devices # (1-4)"); 771da177e4SLinus Torvalds 784a4d2cfdSTakashi Iwai struct snd_card_virmidi { 794a4d2cfdSTakashi Iwai struct snd_card *card; 804a4d2cfdSTakashi Iwai struct snd_rawmidi *midi[MAX_MIDI_DEVICES]; 814a4d2cfdSTakashi Iwai }; 821da177e4SLinus Torvalds 83f7a9275dSClemens Ladisch static struct platform_device *devices[SNDRV_CARDS]; 84f7a9275dSClemens Ladisch 851da177e4SLinus Torvalds 86*fbbb01a1SBill Pemberton static int snd_virmidi_probe(struct platform_device *devptr) 871da177e4SLinus Torvalds { 884a4d2cfdSTakashi Iwai struct snd_card *card; 891da177e4SLinus Torvalds struct snd_card_virmidi *vmidi; 901da177e4SLinus Torvalds int idx, err; 913564fbb8STakashi Iwai int dev = devptr->id; 921da177e4SLinus Torvalds 93bd7dd77cSTakashi Iwai err = snd_card_create(index[dev], id[dev], THIS_MODULE, 94bd7dd77cSTakashi Iwai sizeof(struct snd_card_virmidi), &card); 95bd7dd77cSTakashi Iwai if (err < 0) 96bd7dd77cSTakashi Iwai return err; 979fe856e4SJoe Perches vmidi = card->private_data; 981da177e4SLinus Torvalds vmidi->card = card; 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds if (midi_devs[dev] > MAX_MIDI_DEVICES) { 10145203832STakashi Iwai snd_printk(KERN_WARNING 10245203832STakashi Iwai "too much midi devices for virmidi %d: " 10345203832STakashi Iwai "force to use %d\n", dev, MAX_MIDI_DEVICES); 1041da177e4SLinus Torvalds midi_devs[dev] = MAX_MIDI_DEVICES; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds for (idx = 0; idx < midi_devs[dev]; idx++) { 1074a4d2cfdSTakashi Iwai struct snd_rawmidi *rmidi; 1084a4d2cfdSTakashi Iwai struct snd_virmidi_dev *rdev; 1091da177e4SLinus Torvalds if ((err = snd_virmidi_new(card, idx, &rmidi)) < 0) 1101da177e4SLinus Torvalds goto __nodev; 1111da177e4SLinus Torvalds rdev = rmidi->private_data; 1121da177e4SLinus Torvalds vmidi->midi[idx] = rmidi; 1131da177e4SLinus Torvalds strcpy(rmidi->name, "Virtual Raw MIDI"); 1141da177e4SLinus Torvalds rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH; 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds strcpy(card->driver, "VirMIDI"); 1181da177e4SLinus Torvalds strcpy(card->shortname, "VirMIDI"); 1191da177e4SLinus Torvalds sprintf(card->longname, "Virtual MIDI Card %i", dev + 1); 12016dab54bSTakashi Iwai 1213564fbb8STakashi Iwai snd_card_set_dev(card, &devptr->dev); 12216dab54bSTakashi Iwai 1231da177e4SLinus Torvalds if ((err = snd_card_register(card)) == 0) { 1243564fbb8STakashi Iwai platform_set_drvdata(devptr, card); 1251da177e4SLinus Torvalds return 0; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds __nodev: 1281da177e4SLinus Torvalds snd_card_free(card); 1291da177e4SLinus Torvalds return err; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 132*fbbb01a1SBill Pemberton static int snd_virmidi_remove(struct platform_device *devptr) 1333564fbb8STakashi Iwai { 1343564fbb8STakashi Iwai snd_card_free(platform_get_drvdata(devptr)); 1353564fbb8STakashi Iwai platform_set_drvdata(devptr, NULL); 1363564fbb8STakashi Iwai return 0; 1373564fbb8STakashi Iwai } 1383564fbb8STakashi Iwai 1393564fbb8STakashi Iwai #define SND_VIRMIDI_DRIVER "snd_virmidi" 1403564fbb8STakashi Iwai 1413564fbb8STakashi Iwai static struct platform_driver snd_virmidi_driver = { 1423564fbb8STakashi Iwai .probe = snd_virmidi_probe, 143*fbbb01a1SBill Pemberton .remove = snd_virmidi_remove, 1443564fbb8STakashi Iwai .driver = { 1458bf01d8aSTakashi Iwai .name = SND_VIRMIDI_DRIVER, 1468bf01d8aSTakashi Iwai .owner = THIS_MODULE, 1473564fbb8STakashi Iwai }, 1483564fbb8STakashi Iwai }; 1493564fbb8STakashi Iwai 150bdec0c72SRandy Dunlap static void snd_virmidi_unregister_all(void) 151f7a9275dSClemens Ladisch { 152f7a9275dSClemens Ladisch int i; 153f7a9275dSClemens Ladisch 154f7a9275dSClemens Ladisch for (i = 0; i < ARRAY_SIZE(devices); ++i) 155f7a9275dSClemens Ladisch platform_device_unregister(devices[i]); 156f7a9275dSClemens Ladisch platform_driver_unregister(&snd_virmidi_driver); 157f7a9275dSClemens Ladisch } 158f7a9275dSClemens Ladisch 1591da177e4SLinus Torvalds static int __init alsa_card_virmidi_init(void) 1601da177e4SLinus Torvalds { 1613564fbb8STakashi Iwai int i, cards, err; 1621da177e4SLinus Torvalds 1633564fbb8STakashi Iwai if ((err = platform_driver_register(&snd_virmidi_driver)) < 0) 1643564fbb8STakashi Iwai return err; 1653564fbb8STakashi Iwai 1663564fbb8STakashi Iwai cards = 0; 1678278ca8fSTakashi Iwai for (i = 0; i < SNDRV_CARDS; i++) { 1683564fbb8STakashi Iwai struct platform_device *device; 1698278ca8fSTakashi Iwai if (! enable[i]) 1708278ca8fSTakashi Iwai continue; 1713564fbb8STakashi Iwai device = platform_device_register_simple(SND_VIRMIDI_DRIVER, 1723564fbb8STakashi Iwai i, NULL, 0); 173a182ee98SRene Herman if (IS_ERR(device)) 174a182ee98SRene Herman continue; 1757152447dSRene Herman if (!platform_get_drvdata(device)) { 1767152447dSRene Herman platform_device_unregister(device); 1777152447dSRene Herman continue; 1787152447dSRene Herman } 179f7a9275dSClemens Ladisch devices[i] = device; 1801da177e4SLinus Torvalds cards++; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds if (!cards) { 1831da177e4SLinus Torvalds #ifdef MODULE 1841da177e4SLinus Torvalds printk(KERN_ERR "Card-VirMIDI soundcard not found or device busy\n"); 1851da177e4SLinus Torvalds #endif 186a182ee98SRene Herman snd_virmidi_unregister_all(); 187a182ee98SRene Herman return -ENODEV; 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds return 0; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static void __exit alsa_card_virmidi_exit(void) 1931da177e4SLinus Torvalds { 194f7a9275dSClemens Ladisch snd_virmidi_unregister_all(); 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds module_init(alsa_card_virmidi_init) 1981da177e4SLinus Torvalds module_exit(alsa_card_virmidi_exit) 199