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