1 /* 2 * OSS compatible sequencer driver 3 * 4 * open/close and reset interface 5 * 6 * Copyright (C) 1998-1999 Takashi Iwai <[email protected]> 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 */ 39 static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN; 40 module_param(maxqlen, int, 0444); 41 MODULE_PARM_DESC(maxqlen, "maximum queue length"); 42 43 static int system_client = -1; /* ALSA sequencer client number */ 44 static int system_port = -1; 45 46 static int num_clients; 47 static struct seq_oss_devinfo *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS]; 48 49 50 /* 51 * prototypes 52 */ 53 static int receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop); 54 static int translate_mode(struct file *file); 55 static int create_port(struct seq_oss_devinfo *dp); 56 static int delete_port(struct seq_oss_devinfo *dp); 57 static int alloc_seq_queue(struct seq_oss_devinfo *dp); 58 static int delete_seq_queue(int queue); 59 static 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 */ 65 static void async_call_lookup_ports(struct work_struct *work) 66 { 67 snd_seq_oss_midi_lookup_ports(system_client); 68 } 69 70 static DECLARE_WORK(async_lookup_work, async_call_lookup_ports); 71 72 /* 73 * create sequencer client for OSS sequencer 74 */ 75 int __init 76 snd_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 96 /* create annoucement receiver port */ 97 memset(port, 0, sizeof(*port)); 98 strcpy(port->name, "Receiver"); 99 port->addr.client = system_client; 100 port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */ 101 port->type = 0; 102 103 memset(&port_callback, 0, sizeof(port_callback)); 104 /* don't set port_callback.owner here. otherwise the module counter 105 * is incremented and we can no longer release the module.. 106 */ 107 port_callback.event_input = receive_announce; 108 port->kernel = &port_callback; 109 110 call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port); 111 if ((system_port = port->addr.port) >= 0) { 112 struct snd_seq_port_subscribe subs; 113 114 memset(&subs, 0, sizeof(subs)); 115 subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; 116 subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; 117 subs.dest.client = system_client; 118 subs.dest.port = system_port; 119 call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs); 120 } 121 rc = 0; 122 123 /* look up midi devices */ 124 schedule_work(&async_lookup_work); 125 126 __error: 127 kfree(port); 128 return rc; 129 } 130 131 132 /* 133 * receive annoucement from system port, and check the midi device 134 */ 135 static int 136 receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop) 137 { 138 struct snd_seq_port_info pinfo; 139 140 if (atomic) 141 return 0; /* it must not happen */ 142 143 switch (ev->type) { 144 case SNDRV_SEQ_EVENT_PORT_START: 145 case SNDRV_SEQ_EVENT_PORT_CHANGE: 146 if (ev->data.addr.client == system_client) 147 break; /* ignore myself */ 148 memset(&pinfo, 0, sizeof(pinfo)); 149 pinfo.addr = ev->data.addr; 150 if (call_ctl(SNDRV_SEQ_IOCTL_GET_PORT_INFO, &pinfo) >= 0) 151 snd_seq_oss_midi_check_new_port(&pinfo); 152 break; 153 154 case SNDRV_SEQ_EVENT_PORT_EXIT: 155 if (ev->data.addr.client == system_client) 156 break; /* ignore myself */ 157 snd_seq_oss_midi_check_exit_port(ev->data.addr.client, 158 ev->data.addr.port); 159 break; 160 } 161 return 0; 162 } 163 164 165 /* 166 * delete OSS sequencer client 167 */ 168 int 169 snd_seq_oss_delete_client(void) 170 { 171 cancel_work_sync(&async_lookup_work); 172 if (system_client >= 0) 173 snd_seq_delete_kernel_client(system_client); 174 175 snd_seq_oss_midi_clear_all(); 176 177 return 0; 178 } 179 180 181 /* 182 * open sequencer device 183 */ 184 int 185 snd_seq_oss_open(struct file *file, int level) 186 { 187 int i, rc; 188 struct seq_oss_devinfo *dp; 189 190 dp = kzalloc(sizeof(*dp), GFP_KERNEL); 191 if (!dp) { 192 pr_err("ALSA: seq_oss: can't malloc device info\n"); 193 return -ENOMEM; 194 } 195 196 dp->cseq = system_client; 197 dp->port = -1; 198 dp->queue = -1; 199 200 for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) { 201 if (client_table[i] == NULL) 202 break; 203 } 204 205 dp->index = i; 206 if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { 207 pr_err("ALSA: seq_oss: too many applications\n"); 208 rc = -ENOMEM; 209 goto _error; 210 } 211 212 /* look up synth and midi devices */ 213 snd_seq_oss_synth_setup(dp); 214 snd_seq_oss_midi_setup(dp); 215 216 if (dp->synth_opened == 0 && dp->max_mididev == 0) { 217 /* pr_err("ALSA: seq_oss: no device found\n"); */ 218 rc = -ENODEV; 219 goto _error; 220 } 221 222 /* create port */ 223 rc = create_port(dp); 224 if (rc < 0) { 225 pr_err("ALSA: seq_oss: can't create port\n"); 226 goto _error; 227 } 228 229 /* allocate queue */ 230 rc = alloc_seq_queue(dp); 231 if (rc < 0) 232 goto _error; 233 234 /* set address */ 235 dp->addr.client = dp->cseq; 236 dp->addr.port = dp->port; 237 /*dp->addr.queue = dp->queue;*/ 238 /*dp->addr.channel = 0;*/ 239 240 dp->seq_mode = level; 241 242 /* set up file mode */ 243 dp->file_mode = translate_mode(file); 244 245 /* initialize read queue */ 246 if (is_read_mode(dp->file_mode)) { 247 dp->readq = snd_seq_oss_readq_new(dp, maxqlen); 248 if (!dp->readq) { 249 rc = -ENOMEM; 250 goto _error; 251 } 252 } 253 254 /* initialize write queue */ 255 if (is_write_mode(dp->file_mode)) { 256 dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen); 257 if (!dp->writeq) { 258 rc = -ENOMEM; 259 goto _error; 260 } 261 } 262 263 /* initialize timer */ 264 dp->timer = snd_seq_oss_timer_new(dp); 265 if (!dp->timer) { 266 pr_err("ALSA: seq_oss: can't alloc timer\n"); 267 rc = -ENOMEM; 268 goto _error; 269 } 270 271 /* set private data pointer */ 272 file->private_data = dp; 273 274 /* set up for mode2 */ 275 if (level == SNDRV_SEQ_OSS_MODE_MUSIC) 276 snd_seq_oss_synth_setup_midi(dp); 277 else if (is_read_mode(dp->file_mode)) 278 snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ); 279 280 client_table[dp->index] = dp; 281 num_clients++; 282 283 return 0; 284 285 _error: 286 snd_seq_oss_synth_cleanup(dp); 287 snd_seq_oss_midi_cleanup(dp); 288 delete_seq_queue(dp->queue); 289 delete_port(dp); 290 291 return rc; 292 } 293 294 /* 295 * translate file flags to private mode 296 */ 297 static int 298 translate_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 */ 314 static int 315 create_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 342 return 0; 343 } 344 345 /* 346 * delete ALSA port 347 */ 348 static int 349 delete_port(struct seq_oss_devinfo *dp) 350 { 351 if (dp->port < 0) { 352 kfree(dp); 353 return 0; 354 } 355 356 return snd_seq_event_port_detach(dp->cseq, dp->port); 357 } 358 359 /* 360 * allocate a queue 361 */ 362 static int 363 alloc_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 */ 381 static int 382 delete_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 pr_err("ALSA: 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 */ 401 static void 402 free_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 */ 422 void 423 snd_seq_oss_release(struct seq_oss_devinfo *dp) 424 { 425 int queue; 426 427 client_table[dp->index] = NULL; 428 num_clients--; 429 430 snd_seq_oss_reset(dp); 431 432 snd_seq_oss_synth_cleanup(dp); 433 snd_seq_oss_midi_cleanup(dp); 434 435 /* clear slot */ 436 queue = dp->queue; 437 if (dp->port >= 0) 438 delete_port(dp); 439 delete_seq_queue(queue); 440 } 441 442 443 /* 444 * Wait until the queue is empty (if we don't have nonblock) 445 */ 446 void 447 snd_seq_oss_drain_write(struct seq_oss_devinfo *dp) 448 { 449 if (! dp->timer->running) 450 return; 451 if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) && 452 dp->writeq) { 453 while (snd_seq_oss_writeq_sync(dp->writeq)) 454 ; 455 } 456 } 457 458 459 /* 460 * reset sequencer devices 461 */ 462 void 463 snd_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 */ 492 char * 493 enabled_str(int bool) 494 { 495 return bool ? "enabled" : "disabled"; 496 } 497 498 static char * 499 filemode_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 */ 511 void 512 snd_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