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 */ 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 return -ENOMEM; 193 194 dp->cseq = system_client; 195 dp->port = -1; 196 dp->queue = -1; 197 198 for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) { 199 if (client_table[i] == NULL) 200 break; 201 } 202 203 dp->index = i; 204 if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { 205 pr_debug("ALSA: seq_oss: too many applications\n"); 206 rc = -ENOMEM; 207 goto _error; 208 } 209 210 /* look up synth and midi devices */ 211 snd_seq_oss_synth_setup(dp); 212 snd_seq_oss_midi_setup(dp); 213 214 if (dp->synth_opened == 0 && dp->max_mididev == 0) { 215 /* pr_err("ALSA: seq_oss: no device found\n"); */ 216 rc = -ENODEV; 217 goto _error; 218 } 219 220 /* create port */ 221 rc = create_port(dp); 222 if (rc < 0) { 223 pr_err("ALSA: seq_oss: can't create port\n"); 224 goto _error; 225 } 226 227 /* allocate queue */ 228 rc = alloc_seq_queue(dp); 229 if (rc < 0) 230 goto _error; 231 232 /* set address */ 233 dp->addr.client = dp->cseq; 234 dp->addr.port = dp->port; 235 /*dp->addr.queue = dp->queue;*/ 236 /*dp->addr.channel = 0;*/ 237 238 dp->seq_mode = level; 239 240 /* set up file mode */ 241 dp->file_mode = translate_mode(file); 242 243 /* initialize read queue */ 244 if (is_read_mode(dp->file_mode)) { 245 dp->readq = snd_seq_oss_readq_new(dp, maxqlen); 246 if (!dp->readq) { 247 rc = -ENOMEM; 248 goto _error; 249 } 250 } 251 252 /* initialize write queue */ 253 if (is_write_mode(dp->file_mode)) { 254 dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen); 255 if (!dp->writeq) { 256 rc = -ENOMEM; 257 goto _error; 258 } 259 } 260 261 /* initialize timer */ 262 dp->timer = snd_seq_oss_timer_new(dp); 263 if (!dp->timer) { 264 pr_err("ALSA: seq_oss: can't alloc timer\n"); 265 rc = -ENOMEM; 266 goto _error; 267 } 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 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 */ 295 static int 296 translate_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 */ 312 static int 313 create_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 340 return 0; 341 } 342 343 /* 344 * delete ALSA port 345 */ 346 static int 347 delete_port(struct seq_oss_devinfo *dp) 348 { 349 if (dp->port < 0) { 350 kfree(dp); 351 return 0; 352 } 353 354 return snd_seq_event_port_detach(dp->cseq, dp->port); 355 } 356 357 /* 358 * allocate a queue 359 */ 360 static int 361 alloc_seq_queue(struct seq_oss_devinfo *dp) 362 { 363 struct snd_seq_queue_info qinfo; 364 int rc; 365 366 memset(&qinfo, 0, sizeof(qinfo)); 367 qinfo.owner = system_client; 368 qinfo.locked = 1; 369 strcpy(qinfo.name, "OSS Sequencer Emulation"); 370 if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0) 371 return rc; 372 dp->queue = qinfo.queue; 373 return 0; 374 } 375 376 /* 377 * release queue 378 */ 379 static int 380 delete_seq_queue(int queue) 381 { 382 struct snd_seq_queue_info qinfo; 383 int rc; 384 385 if (queue < 0) 386 return 0; 387 memset(&qinfo, 0, sizeof(qinfo)); 388 qinfo.queue = queue; 389 rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo); 390 if (rc < 0) 391 pr_err("ALSA: seq_oss: unable to delete queue %d (%d)\n", queue, rc); 392 return rc; 393 } 394 395 396 /* 397 * free device informations - private_free callback of port 398 */ 399 static void 400 free_devinfo(void *private) 401 { 402 struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private; 403 404 snd_seq_oss_timer_delete(dp->timer); 405 406 snd_seq_oss_writeq_delete(dp->writeq); 407 408 snd_seq_oss_readq_delete(dp->readq); 409 410 kfree(dp); 411 } 412 413 414 /* 415 * close sequencer device 416 */ 417 void 418 snd_seq_oss_release(struct seq_oss_devinfo *dp) 419 { 420 int queue; 421 422 client_table[dp->index] = NULL; 423 num_clients--; 424 425 snd_seq_oss_reset(dp); 426 427 snd_seq_oss_synth_cleanup(dp); 428 snd_seq_oss_midi_cleanup(dp); 429 430 /* clear slot */ 431 queue = dp->queue; 432 if (dp->port >= 0) 433 delete_port(dp); 434 delete_seq_queue(queue); 435 } 436 437 438 /* 439 * reset sequencer devices 440 */ 441 void 442 snd_seq_oss_reset(struct seq_oss_devinfo *dp) 443 { 444 int i; 445 446 /* reset all synth devices */ 447 for (i = 0; i < dp->max_synthdev; i++) 448 snd_seq_oss_synth_reset(dp, i); 449 450 /* reset all midi devices */ 451 if (dp->seq_mode != SNDRV_SEQ_OSS_MODE_MUSIC) { 452 for (i = 0; i < dp->max_mididev; i++) 453 snd_seq_oss_midi_reset(dp, i); 454 } 455 456 /* remove queues */ 457 if (dp->readq) 458 snd_seq_oss_readq_clear(dp->readq); 459 if (dp->writeq) 460 snd_seq_oss_writeq_clear(dp->writeq); 461 462 /* reset timer */ 463 snd_seq_oss_timer_stop(dp->timer); 464 } 465 466 #ifdef CONFIG_SND_PROC_FS 467 /* 468 * misc. functions for proc interface 469 */ 470 char * 471 enabled_str(int bool) 472 { 473 return bool ? "enabled" : "disabled"; 474 } 475 476 static char * 477 filemode_str(int val) 478 { 479 static char *str[] = { 480 "none", "read", "write", "read/write", 481 }; 482 return str[val & SNDRV_SEQ_OSS_FILE_ACMODE]; 483 } 484 485 486 /* 487 * proc interface 488 */ 489 void 490 snd_seq_oss_system_info_read(struct snd_info_buffer *buf) 491 { 492 int i; 493 struct seq_oss_devinfo *dp; 494 495 snd_iprintf(buf, "ALSA client number %d\n", system_client); 496 snd_iprintf(buf, "ALSA receiver port %d\n", system_port); 497 498 snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients); 499 for (i = 0; i < num_clients; i++) { 500 snd_iprintf(buf, "\nApplication %d: ", i); 501 if ((dp = client_table[i]) == NULL) { 502 snd_iprintf(buf, "*empty*\n"); 503 continue; 504 } 505 snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue); 506 snd_iprintf(buf, " sequencer mode = %s : file open mode = %s\n", 507 (dp->seq_mode ? "music" : "synth"), 508 filemode_str(dp->file_mode)); 509 if (dp->seq_mode) 510 snd_iprintf(buf, " timer tempo = %d, timebase = %d\n", 511 dp->timer->oss_tempo, dp->timer->oss_timebase); 512 snd_iprintf(buf, " max queue length %d\n", maxqlen); 513 if (is_read_mode(dp->file_mode) && dp->readq) 514 snd_seq_oss_readq_info_read(dp->readq, buf); 515 } 516 } 517 #endif /* CONFIG_SND_PROC_FS */ 518