1/* 2 * OSS compatible sequencer driver 3 * 4 * open/close and reset interface 5 * 6 * Copyright (C) 1998-1999 Takashi Iwai <tiwai@suse.de> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23#include "seq_oss_device.h" 24#include "seq_oss_synth.h" 25#include "seq_oss_midi.h" 26#include "seq_oss_writeq.h" 27#include "seq_oss_readq.h" 28#include "seq_oss_timer.h" 29#include "seq_oss_event.h" 30#include <linux/init.h> 31#include <linux/moduleparam.h> 32 33/* 34 * common variables 35 */ 36static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN; 37module_param(maxqlen, int, 0444); 38MODULE_PARM_DESC(maxqlen, "maximum queue length"); 39 40static int system_client = -1; /* ALSA sequencer client number */ 41static int system_port = -1; 42 43static int num_clients; 44static struct seq_oss_devinfo *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS]; 45 46 47/* 48 * prototypes 49 */ 50static int receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop); 51static int translate_mode(struct file *file); 52static int create_port(struct seq_oss_devinfo *dp); 53static int delete_port(struct seq_oss_devinfo *dp); 54static int alloc_seq_queue(struct seq_oss_devinfo *dp); 55static int delete_seq_queue(int queue); 56static void free_devinfo(void *private); 57 58#define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec) 59 60 61/* 62 * create sequencer client for OSS sequencer 63 */ 64int __init 65snd_seq_oss_create_client(void) 66{ 67 int rc; 68 struct snd_seq_port_info *port; 69 struct snd_seq_port_callback port_callback; 70 71 port = kmalloc(sizeof(*port), GFP_KERNEL); 72 if (!port) { 73 rc = -ENOMEM; 74 goto __error; 75 } 76 77 /* create ALSA client */ 78 rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS, 79 "OSS sequencer"); 80 if (rc < 0) 81 goto __error; 82 83 system_client = rc; 84 debug_printk(("new client = %d\n", rc)); 85 86 /* look up midi devices */ 87 snd_seq_oss_midi_lookup_ports(system_client); 88 89 /* create annoucement receiver port */ 90 memset(port, 0, sizeof(*port)); 91 strcpy(port->name, "Receiver"); 92 port->addr.client = system_client; 93 port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */ 94 port->type = 0; 95 96 memset(&port_callback, 0, sizeof(port_callback)); 97 /* don't set port_callback.owner here. otherwise the module counter 98 * is incremented and we can no longer release the module.. 99 */ 100 port_callback.event_input = receive_announce; 101 port->kernel = &port_callback; 102 103 call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port); 104 if ((system_port = port->addr.port) >= 0) { 105 struct snd_seq_port_subscribe subs; 106 107 memset(&subs, 0, sizeof(subs)); 108 subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; 109 subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; 110 subs.dest.client = system_client; 111 subs.dest.port = system_port; 112 call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs); 113 } 114 rc = 0; 115 116 __error: 117 kfree(port); 118 return rc; 119} 120 121 122/* 123 * receive annoucement from system port, and check the midi device 124 */ 125static int 126receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop) 127{ 128 struct snd_seq_port_info pinfo; 129 130 if (atomic) 131 return 0; /* it must not happen */ 132 133 switch (ev->type) { 134 case SNDRV_SEQ_EVENT_PORT_START: 135 case SNDRV_SEQ_EVENT_PORT_CHANGE: 136 if (ev->data.addr.client == system_client) 137 break; /* ignore myself */ 138 memset(&pinfo, 0, sizeof(pinfo)); 139 pinfo.addr = ev->data.addr; 140 if (call_ctl(SNDRV_SEQ_IOCTL_GET_PORT_INFO, &pinfo) >= 0) 141 snd_seq_oss_midi_check_new_port(&pinfo); 142 break; 143 144 case SNDRV_SEQ_EVENT_PORT_EXIT: 145 if (ev->data.addr.client == system_client) 146 break; /* ignore myself */ 147 snd_seq_oss_midi_check_exit_port(ev->data.addr.client, 148 ev->data.addr.port); 149 break; 150 } 151 return 0; 152} 153 154 155/* 156 * delete OSS sequencer client 157 */ 158int 159snd_seq_oss_delete_client(void) 160{ 161 if (system_client >= 0) 162 snd_seq_delete_kernel_client(system_client); 163 164 snd_seq_oss_midi_clear_all(); 165 166 return 0; 167} 168 169 170/* 171 * open sequencer device 172 */ 173int 174snd_seq_oss_open(struct file *file, int level) 175{ 176 int i, rc; 177 struct seq_oss_devinfo *dp; 178 179 if ((dp = kzalloc(sizeof(*dp), GFP_KERNEL)) == NULL) { 180 snd_printk(KERN_ERR "can't malloc device info\n"); 181 return -ENOMEM; 182 } 183 debug_printk(("oss_open: dp = %p\n", dp)); 184 185 for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) { 186 if (client_table[i] == NULL) 187 break; 188 } 189 if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { 190 snd_printk(KERN_ERR "too many applications\n"); 191 kfree(dp); 192 return -ENOMEM; 193 } 194 195 dp->index = i; 196 dp->cseq = system_client; 197 dp->port = -1; 198 dp->queue = -1; 199 dp->readq = NULL; 200 dp->writeq = NULL; 201 202 /* look up synth and midi devices */ 203 snd_seq_oss_synth_setup(dp); 204 snd_seq_oss_midi_setup(dp); 205 206 if (dp->synth_opened == 0 && dp->max_mididev == 0) { 207 /* snd_printk(KERN_ERR "no device found\n"); */ 208 rc = -ENODEV; 209 goto _error; 210 } 211 212 /* create port */ 213 debug_printk(("create new port\n")); 214 if ((rc = create_port(dp)) < 0) { 215 snd_printk(KERN_ERR "can't create port\n"); 216 goto _error; 217 } 218 219 /* allocate queue */ 220 debug_printk(("allocate queue\n")); 221 if ((rc = alloc_seq_queue(dp)) < 0) 222 goto _error; 223 224 /* set address */ 225 dp->addr.client = dp->cseq; 226 dp->addr.port = dp->port; 227 /*dp->addr.queue = dp->queue;*/ 228 /*dp->addr.channel = 0;*/ 229 230 dp->seq_mode = level; 231 232 /* set up file mode */ 233 dp->file_mode = translate_mode(file); 234 235 /* initialize read queue */ 236 debug_printk(("initialize read queue\n")); 237 if (is_read_mode(dp->file_mode)) { 238 if ((dp->readq = snd_seq_oss_readq_new(dp, maxqlen)) == NULL) { 239 rc = -ENOMEM; 240 goto _error; 241 } 242 } 243 244 /* initialize write queue */ 245 debug_printk(("initialize write queue\n")); 246 if (is_write_mode(dp->file_mode)) { 247 dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen); 248 if (dp->writeq == NULL) { 249 rc = -ENOMEM; 250 goto _error; 251 } 252 } 253 254 /* initialize timer */ 255 debug_printk(("initialize timer\n")); 256 if ((dp->timer = snd_seq_oss_timer_new(dp)) == NULL) { 257 snd_printk(KERN_ERR "can't alloc timer\n"); 258 rc = -ENOMEM; 259 goto _error; 260 } 261 debug_printk(("timer initialized\n")); 262 263 /* set private data pointer */ 264 file->private_data = dp; 265 266 /* set up for mode2 */ 267 if (level == SNDRV_SEQ_OSS_MODE_MUSIC) 268 snd_seq_oss_synth_setup_midi(dp); 269 else if (is_read_mode(dp->file_mode)) 270 snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ); 271 272 client_table[dp->index] = dp; 273 num_clients++; 274 275 debug_printk(("open done\n")); 276 return 0; 277 278 _error: 279 snd_seq_oss_synth_cleanup(dp); 280 snd_seq_oss_midi_cleanup(dp); 281 i = dp->queue; 282 delete_port(dp); 283 delete_seq_queue(i); 284 285 return rc; 286} 287 288/* 289 * translate file flags to private mode 290 */ 291static int 292translate_mode(struct file *file) 293{ 294 int file_mode = 0; 295 if ((file->f_flags & O_ACCMODE) != O_RDONLY) 296 file_mode |= SNDRV_SEQ_OSS_FILE_WRITE; 297 if ((file->f_flags & O_ACCMODE) != O_WRONLY) 298 file_mode |= SNDRV_SEQ_OSS_FILE_READ; 299 if (file->f_flags & O_NONBLOCK) 300 file_mode |= SNDRV_SEQ_OSS_FILE_NONBLOCK; 301 return file_mode; 302} 303 304 305/* 306 * create sequencer port 307 */ 308static int 309create_port(struct seq_oss_devinfo *dp) 310{ 311 int rc; 312 struct snd_seq_port_info port; 313 struct snd_seq_port_callback callback; 314 315 memset(&port, 0, sizeof(port)); 316 port.addr.client = dp->cseq; 317 sprintf(port.name, "Sequencer-%d", dp->index); 318 port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_WRITE; /* no subscription */ 319 port.type = SNDRV_SEQ_PORT_TYPE_SPECIFIC; 320 port.midi_channels = 128; 321 port.synth_voices = 128; 322 323 memset(&callback, 0, sizeof(callback)); 324 callback.owner = THIS_MODULE; 325 callback.private_data = dp; 326 callback.event_input = snd_seq_oss_event_input; 327 callback.private_free = free_devinfo; 328 port.kernel = &callback; 329 330 rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port); 331 if (rc < 0) 332 return rc; 333 334 dp->port = port.addr.port; 335 debug_printk(("new port = %d\n", port.addr.port)); 336 337 return 0; 338} 339 340/* 341 * delete ALSA port 342 */ 343static int 344delete_port(struct seq_oss_devinfo *dp) 345{ 346 if (dp->port < 0) 347 return 0; 348 349 debug_printk(("delete_port %i\n", dp->port)); 350 return snd_seq_event_port_detach(dp->cseq, dp->port); 351} 352 353/* 354 * allocate a queue 355 */ 356static int 357alloc_seq_queue(struct seq_oss_devinfo *dp) 358{ 359 struct snd_seq_queue_info qinfo; 360 int rc; 361 362 memset(&qinfo, 0, sizeof(qinfo)); 363 qinfo.owner = system_client; 364 qinfo.locked = 1; 365 strcpy(qinfo.name, "OSS Sequencer Emulation"); 366 if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0) 367 return rc; 368 dp->queue = qinfo.queue; 369 return 0; 370} 371 372/* 373 * release queue 374 */ 375static int 376delete_seq_queue(int queue) 377{ 378 struct snd_seq_queue_info qinfo; 379 int rc; 380 381 if (queue < 0) 382 return 0; 383 memset(&qinfo, 0, sizeof(qinfo)); 384 qinfo.queue = queue; 385 rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo); 386 if (rc < 0) 387 printk(KERN_ERR "seq-oss: unable to delete queue %d (%d)\n", queue, rc); 388 return rc; 389} 390 391 392/* 393 * free device informations - private_free callback of port 394 */ 395static void 396free_devinfo(void *private) 397{ 398 struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private; 399 400 if (dp->timer) 401 snd_seq_oss_timer_delete(dp->timer); 402 403 if (dp->writeq) 404 snd_seq_oss_writeq_delete(dp->writeq); 405 406 if (dp->readq) 407 snd_seq_oss_readq_delete(dp->readq); 408 409 kfree(dp); 410} 411 412 413/* 414 * close sequencer device 415 */ 416void 417snd_seq_oss_release(struct seq_oss_devinfo *dp) 418{ 419 int queue; 420 421 client_table[dp->index] = NULL; 422 num_clients--; 423 424 debug_printk(("resetting..\n")); 425 snd_seq_oss_reset(dp); 426 427 debug_printk(("cleaning up..\n")); 428 snd_seq_oss_synth_cleanup(dp); 429 snd_seq_oss_midi_cleanup(dp); 430 431 /* clear slot */ 432 debug_printk(("releasing resource..\n")); 433 queue = dp->queue; 434 if (dp->port >= 0) 435 delete_port(dp); 436 delete_seq_queue(queue); 437 438 debug_printk(("release done\n")); 439} 440 441 442/* 443 * Wait until the queue is empty (if we don't have nonblock) 444 */ 445void 446snd_seq_oss_drain_write(struct seq_oss_devinfo *dp) 447{ 448 if (! dp->timer->running) 449 return; 450 if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) && 451 dp->writeq) { 452 debug_printk(("syncing..\n")); 453 while (snd_seq_oss_writeq_sync(dp->writeq)) 454 ; 455 } 456} 457 458 459/* 460 * reset sequencer devices 461 */ 462void 463snd_seq_oss_reset(struct seq_oss_devinfo *dp) 464{ 465 int i; 466 467 /* reset all synth devices */ 468 for (i = 0; i < dp->max_synthdev; i++) 469 snd_seq_oss_synth_reset(dp, i); 470 471 /* reset all midi devices */ 472 if (dp->seq_mode != SNDRV_SEQ_OSS_MODE_MUSIC) { 473 for (i = 0; i < dp->max_mididev; i++) 474 snd_seq_oss_midi_reset(dp, i); 475 } 476 477 /* remove queues */ 478 if (dp->readq) 479 snd_seq_oss_readq_clear(dp->readq); 480 if (dp->writeq) 481 snd_seq_oss_writeq_clear(dp->writeq); 482 483 /* reset timer */ 484 snd_seq_oss_timer_stop(dp->timer); 485} 486 487 488#ifdef CONFIG_PROC_FS 489/* 490 * misc. functions for proc interface 491 */ 492char * 493enabled_str(int bool) 494{ 495 return bool ? "enabled" : "disabled"; 496} 497 498static char * 499filemode_str(int val) 500{ 501 static char *str[] = { 502 "none", "read", "write", "read/write", 503 }; 504 return str[val & SNDRV_SEQ_OSS_FILE_ACMODE]; 505} 506 507 508/* 509 * proc interface 510 */ 511void 512snd_seq_oss_system_info_read(struct snd_info_buffer *buf) 513{ 514 int i; 515 struct seq_oss_devinfo *dp; 516 517 snd_iprintf(buf, "ALSA client number %d\n", system_client); 518 snd_iprintf(buf, "ALSA receiver port %d\n", system_port); 519 520 snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients); 521 for (i = 0; i < num_clients; i++) { 522 snd_iprintf(buf, "\nApplication %d: ", i); 523 if ((dp = client_table[i]) == NULL) { 524 snd_iprintf(buf, "*empty*\n"); 525 continue; 526 } 527 snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue); 528 snd_iprintf(buf, " sequencer mode = %s : file open mode = %s\n", 529 (dp->seq_mode ? "music" : "synth"), 530 filemode_str(dp->file_mode)); 531 if (dp->seq_mode) 532 snd_iprintf(buf, " timer tempo = %d, timebase = %d\n", 533 dp->timer->oss_tempo, dp->timer->oss_timebase); 534 snd_iprintf(buf, " max queue length %d\n", maxqlen); 535 if (is_read_mode(dp->file_mode) && dp->readq) 536 snd_seq_oss_readq_info_read(dp->readq, buf); 537 } 538} 539#endif /* CONFIG_PROC_FS */ 540