seq_oss_init.c 12 KB

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