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

Configure Feed

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

at v2.6.25 545 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/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 dp = kzalloc(sizeof(*dp), GFP_KERNEL); 180 if (!dp) { 181 snd_printk(KERN_ERR "can't malloc device info\n"); 182 return -ENOMEM; 183 } 184 debug_printk(("oss_open: dp = %p\n", dp)); 185 186 dp->cseq = system_client; 187 dp->port = -1; 188 dp->queue = -1; 189 190 for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) { 191 if (client_table[i] == NULL) 192 break; 193 } 194 195 dp->index = i; 196 if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { 197 snd_printk(KERN_ERR "too many applications\n"); 198 rc = -ENOMEM; 199 goto _error; 200 } 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 rc = create_port(dp); 215 if (rc < 0) { 216 snd_printk(KERN_ERR "can't create port\n"); 217 goto _error; 218 } 219 220 /* allocate queue */ 221 debug_printk(("allocate queue\n")); 222 rc = alloc_seq_queue(dp); 223 if (rc < 0) 224 goto _error; 225 226 /* set address */ 227 dp->addr.client = dp->cseq; 228 dp->addr.port = dp->port; 229 /*dp->addr.queue = dp->queue;*/ 230 /*dp->addr.channel = 0;*/ 231 232 dp->seq_mode = level; 233 234 /* set up file mode */ 235 dp->file_mode = translate_mode(file); 236 237 /* initialize read queue */ 238 debug_printk(("initialize read queue\n")); 239 if (is_read_mode(dp->file_mode)) { 240 dp->readq = snd_seq_oss_readq_new(dp, maxqlen); 241 if (!dp->readq) { 242 rc = -ENOMEM; 243 goto _error; 244 } 245 } 246 247 /* initialize write queue */ 248 debug_printk(("initialize write queue\n")); 249 if (is_write_mode(dp->file_mode)) { 250 dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen); 251 if (!dp->writeq) { 252 rc = -ENOMEM; 253 goto _error; 254 } 255 } 256 257 /* initialize timer */ 258 debug_printk(("initialize timer\n")); 259 dp->timer = snd_seq_oss_timer_new(dp); 260 if (!dp->timer) { 261 snd_printk(KERN_ERR "can't alloc timer\n"); 262 rc = -ENOMEM; 263 goto _error; 264 } 265 debug_printk(("timer initialized\n")); 266 267 /* set private data pointer */ 268 file->private_data = dp; 269 270 /* set up for mode2 */ 271 if (level == SNDRV_SEQ_OSS_MODE_MUSIC) 272 snd_seq_oss_synth_setup_midi(dp); 273 else if (is_read_mode(dp->file_mode)) 274 snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ); 275 276 client_table[dp->index] = dp; 277 num_clients++; 278 279 debug_printk(("open done\n")); 280 return 0; 281 282 _error: 283 snd_seq_oss_writeq_delete(dp->writeq); 284 snd_seq_oss_readq_delete(dp->readq); 285 snd_seq_oss_synth_cleanup(dp); 286 snd_seq_oss_midi_cleanup(dp); 287 delete_port(dp); 288 delete_seq_queue(dp->queue); 289 kfree(dp); 290 291 return rc; 292} 293 294/* 295 * translate file flags to private mode 296 */ 297static int 298translate_mode(struct file *file) 299{ 300 int file_mode = 0; 301 if ((file->f_flags & O_ACCMODE) != O_RDONLY) 302 file_mode |= SNDRV_SEQ_OSS_FILE_WRITE; 303 if ((file->f_flags & O_ACCMODE) != O_WRONLY) 304 file_mode |= SNDRV_SEQ_OSS_FILE_READ; 305 if (file->f_flags & O_NONBLOCK) 306 file_mode |= SNDRV_SEQ_OSS_FILE_NONBLOCK; 307 return file_mode; 308} 309 310 311/* 312 * create sequencer port 313 */ 314static int 315create_port(struct seq_oss_devinfo *dp) 316{ 317 int rc; 318 struct snd_seq_port_info port; 319 struct snd_seq_port_callback callback; 320 321 memset(&port, 0, sizeof(port)); 322 port.addr.client = dp->cseq; 323 sprintf(port.name, "Sequencer-%d", dp->index); 324 port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_WRITE; /* no subscription */ 325 port.type = SNDRV_SEQ_PORT_TYPE_SPECIFIC; 326 port.midi_channels = 128; 327 port.synth_voices = 128; 328 329 memset(&callback, 0, sizeof(callback)); 330 callback.owner = THIS_MODULE; 331 callback.private_data = dp; 332 callback.event_input = snd_seq_oss_event_input; 333 callback.private_free = free_devinfo; 334 port.kernel = &callback; 335 336 rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port); 337 if (rc < 0) 338 return rc; 339 340 dp->port = port.addr.port; 341 debug_printk(("new port = %d\n", port.addr.port)); 342 343 return 0; 344} 345 346/* 347 * delete ALSA port 348 */ 349static int 350delete_port(struct seq_oss_devinfo *dp) 351{ 352 if (dp->port < 0) 353 return 0; 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 */