seq_oss_init.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. return -ENOMEM;
  161. dp->cseq = system_client;
  162. dp->port = -1;
  163. dp->queue = -1;
  164. for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) {
  165. if (client_table[i] == NULL)
  166. break;
  167. }
  168. dp->index = i;
  169. if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
  170. pr_debug("ALSA: seq_oss: too many applications\n");
  171. rc = -ENOMEM;
  172. goto _error;
  173. }
  174. /* look up synth and midi devices */
  175. snd_seq_oss_synth_setup(dp);
  176. snd_seq_oss_midi_setup(dp);
  177. if (dp->synth_opened == 0 && dp->max_mididev == 0) {
  178. /* pr_err("ALSA: seq_oss: no device found\n"); */
  179. rc = -ENODEV;
  180. goto _error;
  181. }
  182. /* create port */
  183. rc = create_port(dp);
  184. if (rc < 0) {
  185. pr_err("ALSA: seq_oss: can't create port\n");
  186. goto _error;
  187. }
  188. /* allocate queue */
  189. rc = alloc_seq_queue(dp);
  190. if (rc < 0)
  191. goto _error;
  192. /* set address */
  193. dp->addr.client = dp->cseq;
  194. dp->addr.port = dp->port;
  195. /*dp->addr.queue = dp->queue;*/
  196. /*dp->addr.channel = 0;*/
  197. dp->seq_mode = level;
  198. /* set up file mode */
  199. dp->file_mode = translate_mode(file);
  200. /* initialize read queue */
  201. if (is_read_mode(dp->file_mode)) {
  202. dp->readq = snd_seq_oss_readq_new(dp, maxqlen);
  203. if (!dp->readq) {
  204. rc = -ENOMEM;
  205. goto _error;
  206. }
  207. }
  208. /* initialize write queue */
  209. if (is_write_mode(dp->file_mode)) {
  210. dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
  211. if (!dp->writeq) {
  212. rc = -ENOMEM;
  213. goto _error;
  214. }
  215. }
  216. /* initialize timer */
  217. dp->timer = snd_seq_oss_timer_new(dp);
  218. if (!dp->timer) {
  219. pr_err("ALSA: seq_oss: can't alloc timer\n");
  220. rc = -ENOMEM;
  221. goto _error;
  222. }
  223. /* set private data pointer */
  224. file->private_data = dp;
  225. /* set up for mode2 */
  226. if (level == SNDRV_SEQ_OSS_MODE_MUSIC)
  227. snd_seq_oss_synth_setup_midi(dp);
  228. else if (is_read_mode(dp->file_mode))
  229. snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ);
  230. client_table[dp->index] = dp;
  231. num_clients++;
  232. return 0;
  233. _error:
  234. snd_seq_oss_synth_cleanup(dp);
  235. snd_seq_oss_midi_cleanup(dp);
  236. delete_seq_queue(dp->queue);
  237. delete_port(dp);
  238. return rc;
  239. }
  240. /*
  241. * translate file flags to private mode
  242. */
  243. static int
  244. translate_mode(struct file *file)
  245. {
  246. int file_mode = 0;
  247. if ((file->f_flags & O_ACCMODE) != O_RDONLY)
  248. file_mode |= SNDRV_SEQ_OSS_FILE_WRITE;
  249. if ((file->f_flags & O_ACCMODE) != O_WRONLY)
  250. file_mode |= SNDRV_SEQ_OSS_FILE_READ;
  251. if (file->f_flags & O_NONBLOCK)
  252. file_mode |= SNDRV_SEQ_OSS_FILE_NONBLOCK;
  253. return file_mode;
  254. }
  255. /*
  256. * create sequencer port
  257. */
  258. static int
  259. create_port(struct seq_oss_devinfo *dp)
  260. {
  261. int rc;
  262. struct snd_seq_port_info port;
  263. struct snd_seq_port_callback callback;
  264. memset(&port, 0, sizeof(port));
  265. port.addr.client = dp->cseq;
  266. sprintf(port.name, "Sequencer-%d", dp->index);
  267. port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_WRITE; /* no subscription */
  268. port.type = SNDRV_SEQ_PORT_TYPE_SPECIFIC;
  269. port.midi_channels = 128;
  270. port.synth_voices = 128;
  271. memset(&callback, 0, sizeof(callback));
  272. callback.owner = THIS_MODULE;
  273. callback.private_data = dp;
  274. callback.event_input = snd_seq_oss_event_input;
  275. callback.private_free = free_devinfo;
  276. port.kernel = &callback;
  277. rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
  278. if (rc < 0)
  279. return rc;
  280. dp->port = port.addr.port;
  281. return 0;
  282. }
  283. /*
  284. * delete ALSA port
  285. */
  286. static int
  287. delete_port(struct seq_oss_devinfo *dp)
  288. {
  289. if (dp->port < 0) {
  290. kfree(dp);
  291. return 0;
  292. }
  293. return snd_seq_event_port_detach(dp->cseq, dp->port);
  294. }
  295. /*
  296. * allocate a queue
  297. */
  298. static int
  299. alloc_seq_queue(struct seq_oss_devinfo *dp)
  300. {
  301. struct snd_seq_queue_info qinfo;
  302. int rc;
  303. memset(&qinfo, 0, sizeof(qinfo));
  304. qinfo.owner = system_client;
  305. qinfo.locked = 1;
  306. strcpy(qinfo.name, "OSS Sequencer Emulation");
  307. if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0)
  308. return rc;
  309. dp->queue = qinfo.queue;
  310. return 0;
  311. }
  312. /*
  313. * release queue
  314. */
  315. static int
  316. delete_seq_queue(int queue)
  317. {
  318. struct snd_seq_queue_info qinfo;
  319. int rc;
  320. if (queue < 0)
  321. return 0;
  322. memset(&qinfo, 0, sizeof(qinfo));
  323. qinfo.queue = queue;
  324. rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
  325. if (rc < 0)
  326. pr_err("ALSA: seq_oss: unable to delete queue %d (%d)\n", queue, rc);
  327. return rc;
  328. }
  329. /*
  330. * free device informations - private_free callback of port
  331. */
  332. static void
  333. free_devinfo(void *private)
  334. {
  335. struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private;
  336. snd_seq_oss_timer_delete(dp->timer);
  337. snd_seq_oss_writeq_delete(dp->writeq);
  338. snd_seq_oss_readq_delete(dp->readq);
  339. kfree(dp);
  340. }
  341. /*
  342. * close sequencer device
  343. */
  344. void
  345. snd_seq_oss_release(struct seq_oss_devinfo *dp)
  346. {
  347. int queue;
  348. client_table[dp->index] = NULL;
  349. num_clients--;
  350. snd_seq_oss_reset(dp);
  351. snd_seq_oss_synth_cleanup(dp);
  352. snd_seq_oss_midi_cleanup(dp);
  353. /* clear slot */
  354. queue = dp->queue;
  355. if (dp->port >= 0)
  356. delete_port(dp);
  357. delete_seq_queue(queue);
  358. }
  359. /*
  360. * reset sequencer devices
  361. */
  362. void
  363. snd_seq_oss_reset(struct seq_oss_devinfo *dp)
  364. {
  365. int i;
  366. /* reset all synth devices */
  367. for (i = 0; i < dp->max_synthdev; i++)
  368. snd_seq_oss_synth_reset(dp, i);
  369. /* reset all midi devices */
  370. if (dp->seq_mode != SNDRV_SEQ_OSS_MODE_MUSIC) {
  371. for (i = 0; i < dp->max_mididev; i++)
  372. snd_seq_oss_midi_reset(dp, i);
  373. }
  374. /* remove queues */
  375. if (dp->readq)
  376. snd_seq_oss_readq_clear(dp->readq);
  377. if (dp->writeq)
  378. snd_seq_oss_writeq_clear(dp->writeq);
  379. /* reset timer */
  380. snd_seq_oss_timer_stop(dp->timer);
  381. }
  382. #ifdef CONFIG_SND_PROC_FS
  383. /*
  384. * misc. functions for proc interface
  385. */
  386. char *
  387. enabled_str(int bool)
  388. {
  389. return bool ? "enabled" : "disabled";
  390. }
  391. static char *
  392. filemode_str(int val)
  393. {
  394. static char *str[] = {
  395. "none", "read", "write", "read/write",
  396. };
  397. return str[val & SNDRV_SEQ_OSS_FILE_ACMODE];
  398. }
  399. /*
  400. * proc interface
  401. */
  402. void
  403. snd_seq_oss_system_info_read(struct snd_info_buffer *buf)
  404. {
  405. int i;
  406. struct seq_oss_devinfo *dp;
  407. snd_iprintf(buf, "ALSA client number %d\n", system_client);
  408. snd_iprintf(buf, "ALSA receiver port %d\n", system_port);
  409. snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients);
  410. for (i = 0; i < num_clients; i++) {
  411. snd_iprintf(buf, "\nApplication %d: ", i);
  412. if ((dp = client_table[i]) == NULL) {
  413. snd_iprintf(buf, "*empty*\n");
  414. continue;
  415. }
  416. snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue);
  417. snd_iprintf(buf, " sequencer mode = %s : file open mode = %s\n",
  418. (dp->seq_mode ? "music" : "synth"),
  419. filemode_str(dp->file_mode));
  420. if (dp->seq_mode)
  421. snd_iprintf(buf, " timer tempo = %d, timebase = %d\n",
  422. dp->timer->oss_tempo, dp->timer->oss_timebase);
  423. snd_iprintf(buf, " max queue length %d\n", maxqlen);
  424. if (is_read_mode(dp->file_mode) && dp->readq)
  425. snd_seq_oss_readq_info_read(dp->readq, buf);
  426. }
  427. }
  428. #endif /* CONFIG_SND_PROC_FS */