Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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