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