1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
4 | * and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk> |
5 | * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de> |
6 | * |
7 | * Emu8000 synth plug-in routine |
8 | */ |
9 | |
10 | #include "emu8000_local.h" |
11 | #include <linux/init.h> |
12 | #include <linux/module.h> |
13 | #include <sound/initval.h> |
14 | |
15 | MODULE_AUTHOR("Takashi Iwai, Steve Ratcliffe" ); |
16 | MODULE_DESCRIPTION("Emu8000 synth plug-in routine" ); |
17 | MODULE_LICENSE("GPL" ); |
18 | |
19 | /*----------------------------------------------------------------*/ |
20 | |
21 | /* |
22 | * create a new hardware dependent device for Emu8000 |
23 | */ |
24 | static int snd_emu8000_probe(struct device *_dev) |
25 | { |
26 | struct snd_seq_device *dev = to_seq_dev(_dev); |
27 | struct snd_emu8000 *hw; |
28 | struct snd_emux *emu; |
29 | |
30 | hw = *(struct snd_emu8000**)SNDRV_SEQ_DEVICE_ARGPTR(dev); |
31 | if (hw == NULL) |
32 | return -EINVAL; |
33 | |
34 | if (hw->emu) |
35 | return -EBUSY; /* already exists..? */ |
36 | |
37 | if (snd_emux_new(remu: &emu) < 0) |
38 | return -ENOMEM; |
39 | |
40 | hw->emu = emu; |
41 | snd_emu8000_ops_setup(emu: hw); |
42 | |
43 | emu->hw = hw; |
44 | emu->max_voices = EMU8000_DRAM_VOICES; |
45 | emu->num_ports = hw->seq_ports; |
46 | |
47 | if (hw->memhdr) { |
48 | snd_printk(KERN_ERR "memhdr is already initialized!?\n" ); |
49 | snd_util_memhdr_free(hdr: hw->memhdr); |
50 | } |
51 | hw->memhdr = snd_util_memhdr_new(memsize: hw->mem_size); |
52 | if (hw->memhdr == NULL) { |
53 | snd_emux_free(emu); |
54 | hw->emu = NULL; |
55 | return -ENOMEM; |
56 | } |
57 | |
58 | emu->memhdr = hw->memhdr; |
59 | emu->midi_ports = hw->seq_ports < 2 ? hw->seq_ports : 2; /* number of virmidi ports */ |
60 | emu->midi_devidx = 1; |
61 | emu->linear_panning = 1; |
62 | emu->hwdep_idx = 2; /* FIXED */ |
63 | |
64 | if (snd_emux_register(emu, card: dev->card, index: hw->index, name: "Emu8000" ) < 0) { |
65 | snd_emux_free(emu); |
66 | snd_util_memhdr_free(hdr: hw->memhdr); |
67 | hw->emu = NULL; |
68 | hw->memhdr = NULL; |
69 | return -ENOMEM; |
70 | } |
71 | |
72 | if (hw->mem_size > 0) |
73 | snd_emu8000_pcm_new(card: dev->card, emu: hw, index: 1); |
74 | |
75 | dev->driver_data = hw; |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | |
81 | /* |
82 | * free all resources |
83 | */ |
84 | static int snd_emu8000_remove(struct device *_dev) |
85 | { |
86 | struct snd_seq_device *dev = to_seq_dev(_dev); |
87 | struct snd_emu8000 *hw; |
88 | |
89 | if (dev->driver_data == NULL) |
90 | return 0; /* no synth was allocated actually */ |
91 | |
92 | hw = dev->driver_data; |
93 | if (hw->pcm) |
94 | snd_device_free(card: dev->card, device_data: hw->pcm); |
95 | snd_emux_free(emu: hw->emu); |
96 | snd_util_memhdr_free(hdr: hw->memhdr); |
97 | hw->emu = NULL; |
98 | hw->memhdr = NULL; |
99 | return 0; |
100 | } |
101 | |
102 | /* |
103 | * INIT part |
104 | */ |
105 | |
106 | static struct snd_seq_driver emu8000_driver = { |
107 | .driver = { |
108 | .name = KBUILD_MODNAME, |
109 | .probe = snd_emu8000_probe, |
110 | .remove = snd_emu8000_remove, |
111 | }, |
112 | .id = SNDRV_SEQ_DEV_ID_EMU8000, |
113 | .argsize = sizeof(struct snd_emu8000 *), |
114 | }; |
115 | |
116 | module_snd_seq_driver(emu8000_driver); |
117 | |