diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-31 18:16:28 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-31 18:16:28 -0500 |
commit | e1a9c9872dd004617555dff079b357a6ffd945e9 (patch) | |
tree | c34779e59712ff345f8e4ee97e74086a85b34974 /sound/drivers | |
parent | fcc3ff4f9d695a80dc6e6058e0d631a3026ed4c3 (diff) | |
parent | 2ecba4ffbbc6c85fce8c3878514be415edace413 (diff) |
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa
* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa: (299 commits)
[ALSA] version 1.0.16rc2
[ALSA] hda: fix Mic in as output
[ALSA] emu10k1 - Another EMU0404 Board ID
[ALSA] emu10k1 - Fix kthread handling at resume
[ALSA] emu10k1: General cleanup, add new locks, fix alsa bug#3501, kernel bug#9304.
[ALSA] emu10k1 - Use enum for emu_model types
[ALSA] emu10k1 - Don't create emu1010 controls for non-emu boards
[ALSA] emu10k1 - 1616(M) cardbus improvements
[ALSA] snd:emu10k1: E-Mu updates. Fixes to firmware loading and support for 0404.
[ALSA] emu10k1: Add comments regarding E-Mu ins and outs.
[ALSA] oxygen: revert SPI clock frequency change for AK4396/WM8785
[ALSA] es1938 - improve capture hw pointer reads
[ALSA] HDA-Intel - Add support for Intel SCH
[ALSA] hda: Add GPIO mute support to STAC9205
[ALSA] hda-codec - Add Dell T3400 support
[ALSA] hda-codec - Add model for HP DV9553EG laptop
[ALSA] hda-codec - Control SPDIF as slave
[ALSA] hda_intel: ALSA HD Audio patch for Intel ICH10 DeviceID's
[ALSA] Fix Oops with PCM OSS sync
[ALSA] hda-codec - Add speaker automute to ALC262 HP models
...
Diffstat (limited to 'sound/drivers')
-rw-r--r-- | sound/drivers/Kconfig | 12 | ||||
-rw-r--r-- | sound/drivers/Makefile | 2 | ||||
-rw-r--r-- | sound/drivers/dummy.c | 1 | ||||
-rw-r--r-- | sound/drivers/ml403-ac97cr.c | 1352 | ||||
-rw-r--r-- | sound/drivers/mpu401/mpu401.c | 1 | ||||
-rw-r--r-- | sound/drivers/mpu401/mpu401_uart.c | 1 | ||||
-rw-r--r-- | sound/drivers/mtpav.c | 1 | ||||
-rw-r--r-- | sound/drivers/mts64.c | 17 | ||||
-rw-r--r-- | sound/drivers/opl3/opl3_lib.c | 5 | ||||
-rw-r--r-- | sound/drivers/opl3/opl3_midi.c | 41 | ||||
-rw-r--r-- | sound/drivers/opl3/opl3_oss.c | 135 | ||||
-rw-r--r-- | sound/drivers/opl3/opl3_seq.c | 42 | ||||
-rw-r--r-- | sound/drivers/opl3/opl3_synth.c | 180 | ||||
-rw-r--r-- | sound/drivers/pcm-indirect2.c | 573 | ||||
-rw-r--r-- | sound/drivers/pcm-indirect2.h | 140 | ||||
-rw-r--r-- | sound/drivers/portman2x4.c | 3 | ||||
-rw-r--r-- | sound/drivers/serial-u16550.c | 10 | ||||
-rw-r--r-- | sound/drivers/virmidi.c | 1 | ||||
-rw-r--r-- | sound/drivers/vx/vx_cmd.c | 1 | ||||
-rw-r--r-- | sound/drivers/vx/vx_core.c | 1 | ||||
-rw-r--r-- | sound/drivers/vx/vx_hwdep.c | 1 | ||||
-rw-r--r-- | sound/drivers/vx/vx_mixer.c | 68 | ||||
-rw-r--r-- | sound/drivers/vx/vx_pcm.c | 1 | ||||
-rw-r--r-- | sound/drivers/vx/vx_uer.c | 1 |
24 files changed, 2373 insertions, 217 deletions
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 83529b08d019..75d4fe09fdf3 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -120,4 +120,16 @@ config SND_PORTMAN2X4 | |||
120 | To compile this driver as a module, choose M here: the module | 120 | To compile this driver as a module, choose M here: the module |
121 | will be called snd-portman2x4. | 121 | will be called snd-portman2x4. |
122 | 122 | ||
123 | config SND_ML403_AC97CR | ||
124 | tristate "Xilinx ML403 AC97 Controller Reference" | ||
125 | depends on SND && XILINX_VIRTEX | ||
126 | select SND_AC97_CODEC | ||
127 | help | ||
128 | Say Y here to include support for the | ||
129 | opb_ac97_controller_ref_v1_00_a ip core found in Xilinx' ML403 | ||
130 | reference design. | ||
131 | |||
132 | To compile this driver as a module, choose M here: the module | ||
133 | will be called snd-ml403_ac97cr. | ||
134 | |||
123 | endmenu | 135 | endmenu |
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index 80aeff5ccdea..8e5530006e1f 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile | |||
@@ -9,6 +9,7 @@ snd-mts64-objs := mts64.o | |||
9 | snd-portman2x4-objs := portman2x4.o | 9 | snd-portman2x4-objs := portman2x4.o |
10 | snd-serial-u16550-objs := serial-u16550.o | 10 | snd-serial-u16550-objs := serial-u16550.o |
11 | snd-virmidi-objs := virmidi.o | 11 | snd-virmidi-objs := virmidi.o |
12 | snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o | ||
12 | 13 | ||
13 | # Toplevel Module Dependency | 14 | # Toplevel Module Dependency |
14 | obj-$(CONFIG_SND_DUMMY) += snd-dummy.o | 15 | obj-$(CONFIG_SND_DUMMY) += snd-dummy.o |
@@ -17,5 +18,6 @@ obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o | |||
17 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o | 18 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o |
18 | obj-$(CONFIG_SND_MTS64) += snd-mts64.o | 19 | obj-$(CONFIG_SND_MTS64) += snd-mts64.o |
19 | obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o | 20 | obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o |
21 | obj-$(CONFIG_SND_ML403_AC97CR) += snd-ml403-ac97cr.o | ||
20 | 22 | ||
21 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ | 23 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index e008f3c58eac..a240eaeb5c62 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/err.h> | 22 | #include <linux/err.h> |
24 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c new file mode 100644 index 000000000000..05a871aa7b81 --- /dev/null +++ b/sound/drivers/ml403-ac97cr.c | |||
@@ -0,0 +1,1352 @@ | |||
1 | /* | ||
2 | * ALSA driver for Xilinx ML403 AC97 Controller Reference | ||
3 | * IP: opb_ac97_controller_ref_v1_00_a (EDK 8.1i) | ||
4 | * IP: opb_ac97_controller_ref_v1_00_a (EDK 9.1i) | ||
5 | * | ||
6 | * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.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 | |||
24 | /* Some notes / status of this driver: | ||
25 | * | ||
26 | * - Don't wonder about some strange implementations of things - especially the | ||
27 | * (heavy) shadowing of codec registers, with which I tried to reduce read | ||
28 | * accesses to a minimum, because after a variable amount of accesses, the AC97 | ||
29 | * controller doesn't raise the register access finished bit anymore ... | ||
30 | * | ||
31 | * - Playback support seems to be pretty stable - no issues here. | ||
32 | * - Capture support "works" now, too. Overruns don't happen any longer so often. | ||
33 | * But there might still be some ... | ||
34 | */ | ||
35 | |||
36 | #include <linux/init.h> | ||
37 | #include <linux/moduleparam.h> | ||
38 | |||
39 | #include <linux/platform_device.h> | ||
40 | |||
41 | #include <linux/ioport.h> | ||
42 | #include <linux/io.h> | ||
43 | #include <linux/interrupt.h> | ||
44 | |||
45 | /* HZ */ | ||
46 | #include <linux/param.h> | ||
47 | /* jiffies, time_*() */ | ||
48 | #include <linux/jiffies.h> | ||
49 | /* schedule_timeout*() */ | ||
50 | #include <linux/sched.h> | ||
51 | /* spin_lock*() */ | ||
52 | #include <linux/spinlock.h> | ||
53 | /* struct mutex, mutex_init(), mutex_*lock() */ | ||
54 | #include <linux/mutex.h> | ||
55 | |||
56 | /* snd_printk(), snd_printd() */ | ||
57 | #include <sound/core.h> | ||
58 | #include <sound/pcm.h> | ||
59 | #include <sound/pcm_params.h> | ||
60 | #include <sound/initval.h> | ||
61 | #include <sound/ac97_codec.h> | ||
62 | |||
63 | #include "pcm-indirect2.h" | ||
64 | |||
65 | |||
66 | #define SND_ML403_AC97CR_DRIVER "ml403-ac97cr" | ||
67 | |||
68 | MODULE_AUTHOR("Joachim Foerster <JOFT@gmx.de>"); | ||
69 | MODULE_DESCRIPTION("Xilinx ML403 AC97 Controller Reference"); | ||
70 | MODULE_LICENSE("GPL"); | ||
71 | MODULE_SUPPORTED_DEVICE("{{Xilinx,ML403 AC97 Controller Reference}}"); | ||
72 | |||
73 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
74 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
75 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; | ||
76 | |||
77 | module_param_array(index, int, NULL, 0444); | ||
78 | MODULE_PARM_DESC(index, "Index value for ML403 AC97 Controller Reference."); | ||
79 | module_param_array(id, charp, NULL, 0444); | ||
80 | MODULE_PARM_DESC(id, "ID string for ML403 AC97 Controller Reference."); | ||
81 | module_param_array(enable, bool, NULL, 0444); | ||
82 | MODULE_PARM_DESC(enable, "Enable this ML403 AC97 Controller Reference."); | ||
83 | |||
84 | /* Special feature options */ | ||
85 | /*#define CODEC_WRITE_CHECK_RAF*/ /* don't return after a write to a codec | ||
86 | * register, while RAF bit is not set | ||
87 | */ | ||
88 | /* Debug options for code which may be removed completely in a final version */ | ||
89 | #ifdef CONFIG_SND_DEBUG | ||
90 | /*#define CODEC_STAT*/ /* turn on some minimal "statistics" | ||
91 | * about codec register usage | ||
92 | */ | ||
93 | #define SND_PCM_INDIRECT2_STAT /* turn on some "statistics" about the | ||
94 | * process of copying bytes from the | ||
95 | * intermediate buffer to the hardware | ||
96 | * fifo and the other way round | ||
97 | */ | ||
98 | #endif | ||
99 | |||
100 | /* Definition of a "level/facility dependent" printk(); may be removed | ||
101 | * completely in a final version | ||
102 | */ | ||
103 | #undef PDEBUG | ||
104 | #ifdef CONFIG_SND_DEBUG | ||
105 | /* "facilities" for PDEBUG */ | ||
106 | #define UNKNOWN (1<<0) | ||
107 | #define CODEC_SUCCESS (1<<1) | ||
108 | #define CODEC_FAKE (1<<2) | ||
109 | #define INIT_INFO (1<<3) | ||
110 | #define INIT_FAILURE (1<<4) | ||
111 | #define WORK_INFO (1<<5) | ||
112 | #define WORK_FAILURE (1<<6) | ||
113 | |||
114 | #define PDEBUG_FACILITIES (UNKNOWN | INIT_FAILURE | WORK_FAILURE) | ||
115 | |||
116 | #define PDEBUG(fac, fmt, args...) do { \ | ||
117 | if (fac & PDEBUG_FACILITIES) \ | ||
118 | snd_printd(KERN_DEBUG SND_ML403_AC97CR_DRIVER ": " \ | ||
119 | fmt, ##args); \ | ||
120 | } while (0) | ||
121 | #else | ||
122 | #define PDEBUG(fac, fmt, args...) /* nothing */ | ||
123 | #endif | ||
124 | |||
125 | |||
126 | |||
127 | /* Defines for "waits"/timeouts (portions of HZ=250 on arch/ppc by default) */ | ||
128 | #define CODEC_TIMEOUT_ON_INIT 5 /* timeout for checking for codec | ||
129 | * readiness (after insmod) | ||
130 | */ | ||
131 | #ifndef CODEC_WRITE_CHECK_RAF | ||
132 | #define CODEC_WAIT_AFTER_WRITE 100 /* general, static wait after a write | ||
133 | * access to a codec register, may be | ||
134 | * 0 to completely remove wait | ||
135 | */ | ||
136 | #else | ||
137 | #define CODEC_TIMEOUT_AFTER_WRITE 5 /* timeout after a write access to a | ||
138 | * codec register, if RAF bit is used | ||
139 | */ | ||
140 | #endif | ||
141 | #define CODEC_TIMEOUT_AFTER_READ 5 /* timeout after a read access to a | ||
142 | * codec register (checking RAF bit) | ||
143 | */ | ||
144 | |||
145 | /* Infrastructure for codec register shadowing */ | ||
146 | #define LM4550_REG_OK (1<<0) /* register exists */ | ||
147 | #define LM4550_REG_DONEREAD (1<<1) /* read register once, value should be | ||
148 | * the same currently in the register | ||
149 | */ | ||
150 | #define LM4550_REG_NOSAVE (1<<2) /* values written to this register will | ||
151 | * not be saved in the register | ||
152 | */ | ||
153 | #define LM4550_REG_NOSHADOW (1<<3) /* don't do register shadowing, use plain | ||
154 | * hardware access | ||
155 | */ | ||
156 | #define LM4550_REG_READONLY (1<<4) /* register is read only */ | ||
157 | #define LM4550_REG_FAKEPROBE (1<<5) /* fake write _and_ read actions during | ||
158 | * probe() correctly | ||
159 | */ | ||
160 | #define LM4550_REG_FAKEREAD (1<<6) /* fake read access, always return | ||
161 | * default value | ||
162 | */ | ||
163 | #define LM4550_REG_ALLFAKE (LM4550_REG_FAKEREAD | LM4550_REG_FAKEPROBE) | ||
164 | |||
165 | struct lm4550_reg { | ||
166 | u16 value; | ||
167 | u16 flag; | ||
168 | u16 wmask; | ||
169 | u16 def; | ||
170 | }; | ||
171 | |||
172 | struct lm4550_reg lm4550_regfile[64] = { | ||
173 | [AC97_RESET / 2] = {.flag = LM4550_REG_OK \ | ||
174 | | LM4550_REG_NOSAVE \ | ||
175 | | LM4550_REG_FAKEREAD, | ||
176 | .def = 0x0D50}, | ||
177 | [AC97_MASTER / 2] = {.flag = LM4550_REG_OK | ||
178 | | LM4550_REG_FAKEPROBE, | ||
179 | .wmask = 0x9F1F, | ||
180 | .def = 0x8000}, | ||
181 | [AC97_HEADPHONE / 2] = {.flag = LM4550_REG_OK \ | ||
182 | | LM4550_REG_FAKEPROBE, | ||
183 | .wmask = 0x9F1F, | ||
184 | .def = 0x8000}, | ||
185 | [AC97_MASTER_MONO / 2] = {.flag = LM4550_REG_OK \ | ||
186 | | LM4550_REG_FAKEPROBE, | ||
187 | .wmask = 0x801F, | ||
188 | .def = 0x8000}, | ||
189 | [AC97_PC_BEEP / 2] = {.flag = LM4550_REG_OK \ | ||
190 | | LM4550_REG_FAKEPROBE, | ||
191 | .wmask = 0x801E, | ||
192 | .def = 0x0}, | ||
193 | [AC97_PHONE / 2] = {.flag = LM4550_REG_OK \ | ||
194 | | LM4550_REG_FAKEPROBE, | ||
195 | .wmask = 0x801F, | ||
196 | .def = 0x8008}, | ||
197 | [AC97_MIC / 2] = {.flag = LM4550_REG_OK \ | ||
198 | | LM4550_REG_FAKEPROBE, | ||
199 | .wmask = 0x805F, | ||
200 | .def = 0x8008}, | ||
201 | [AC97_LINE / 2] = {.flag = LM4550_REG_OK \ | ||
202 | | LM4550_REG_FAKEPROBE, | ||
203 | .wmask = 0x9F1F, | ||
204 | .def = 0x8808}, | ||
205 | [AC97_CD / 2] = {.flag = LM4550_REG_OK \ | ||
206 | | LM4550_REG_FAKEPROBE, | ||
207 | .wmask = 0x9F1F, | ||
208 | .def = 0x8808}, | ||
209 | [AC97_VIDEO / 2] = {.flag = LM4550_REG_OK \ | ||
210 | | LM4550_REG_FAKEPROBE, | ||
211 | .wmask = 0x9F1F, | ||
212 | .def = 0x8808}, | ||
213 | [AC97_AUX / 2] = {.flag = LM4550_REG_OK \ | ||
214 | | LM4550_REG_FAKEPROBE, | ||
215 | .wmask = 0x9F1F, | ||
216 | .def = 0x8808}, | ||
217 | [AC97_PCM / 2] = {.flag = LM4550_REG_OK \ | ||
218 | | LM4550_REG_FAKEPROBE, | ||
219 | .wmask = 0x9F1F, | ||
220 | .def = 0x8008}, | ||
221 | [AC97_REC_SEL / 2] = {.flag = LM4550_REG_OK \ | ||
222 | | LM4550_REG_FAKEPROBE, | ||
223 | .wmask = 0x707, | ||
224 | .def = 0x0}, | ||
225 | [AC97_REC_GAIN / 2] = {.flag = LM4550_REG_OK \ | ||
226 | | LM4550_REG_FAKEPROBE, | ||
227 | .wmask = 0x8F0F, | ||
228 | .def = 0x8000}, | ||
229 | [AC97_GENERAL_PURPOSE / 2] = {.flag = LM4550_REG_OK \ | ||
230 | | LM4550_REG_FAKEPROBE, | ||
231 | .def = 0x0, | ||
232 | .wmask = 0xA380}, | ||
233 | [AC97_3D_CONTROL / 2] = {.flag = LM4550_REG_OK \ | ||
234 | | LM4550_REG_FAKEREAD \ | ||
235 | | LM4550_REG_READONLY, | ||
236 | .def = 0x0101}, | ||
237 | [AC97_POWERDOWN / 2] = {.flag = LM4550_REG_OK \ | ||
238 | | LM4550_REG_NOSHADOW \ | ||
239 | | LM4550_REG_NOSAVE, | ||
240 | .wmask = 0xFF00}, | ||
241 | /* may not write ones to | ||
242 | * REF/ANL/DAC/ADC bits | ||
243 | * FIXME: Is this ok? | ||
244 | */ | ||
245 | [AC97_EXTENDED_ID / 2] = {.flag = LM4550_REG_OK \ | ||
246 | | LM4550_REG_FAKEREAD \ | ||
247 | | LM4550_REG_READONLY, | ||
248 | .def = 0x0201}, /* primary codec */ | ||
249 | [AC97_EXTENDED_STATUS / 2] = {.flag = LM4550_REG_OK \ | ||
250 | | LM4550_REG_NOSHADOW \ | ||
251 | | LM4550_REG_NOSAVE, | ||
252 | .wmask = 0x1}, | ||
253 | [AC97_PCM_FRONT_DAC_RATE / 2] = {.flag = LM4550_REG_OK \ | ||
254 | | LM4550_REG_FAKEPROBE, | ||
255 | .def = 0xBB80, | ||
256 | .wmask = 0xFFFF}, | ||
257 | [AC97_PCM_LR_ADC_RATE / 2] = {.flag = LM4550_REG_OK \ | ||
258 | | LM4550_REG_FAKEPROBE, | ||
259 | .def = 0xBB80, | ||
260 | .wmask = 0xFFFF}, | ||
261 | [AC97_VENDOR_ID1 / 2] = {.flag = LM4550_REG_OK \ | ||
262 | | LM4550_REG_READONLY \ | ||
263 | | LM4550_REG_FAKEREAD, | ||
264 | .def = 0x4E53}, | ||
265 | [AC97_VENDOR_ID2 / 2] = {.flag = LM4550_REG_OK \ | ||
266 | | LM4550_REG_READONLY \ | ||
267 | | LM4550_REG_FAKEREAD, | ||
268 | .def = 0x4350} | ||
269 | }; | ||
270 | |||
271 | #define LM4550_RF_OK(reg) (lm4550_regfile[reg / 2].flag & LM4550_REG_OK) | ||
272 | |||
273 | static void lm4550_regfile_init(void) | ||
274 | { | ||
275 | int i; | ||
276 | for (i = 0; i < 64; i++) | ||
277 | if (lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) | ||
278 | lm4550_regfile[i].value = lm4550_regfile[i].def; | ||
279 | } | ||
280 | |||
281 | static void lm4550_regfile_write_values_after_init(struct snd_ac97 *ac97) | ||
282 | { | ||
283 | int i; | ||
284 | for (i = 0; i < 64; i++) | ||
285 | if ((lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) && | ||
286 | (lm4550_regfile[i].value != lm4550_regfile[i].def)) { | ||
287 | PDEBUG(CODEC_FAKE, "lm4550_regfile_write_values_after_" | ||
288 | "init(): reg=0x%x value=0x%x / %d is different " | ||
289 | "from def=0x%x / %d\n", | ||
290 | i, lm4550_regfile[i].value, | ||
291 | lm4550_regfile[i].value, lm4550_regfile[i].def, | ||
292 | lm4550_regfile[i].def); | ||
293 | snd_ac97_write(ac97, i * 2, lm4550_regfile[i].value); | ||
294 | lm4550_regfile[i].flag |= LM4550_REG_DONEREAD; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | |||
299 | /* direct registers */ | ||
300 | #define CR_REG(ml403_ac97cr, x) ((ml403_ac97cr)->port + CR_REG_##x) | ||
301 | |||
302 | #define CR_REG_PLAYFIFO 0x00 | ||
303 | #define CR_PLAYDATA(a) ((a) & 0xFFFF) | ||
304 | |||
305 | #define CR_REG_RECFIFO 0x04 | ||
306 | #define CR_RECDATA(a) ((a) & 0xFFFF) | ||
307 | |||
308 | #define CR_REG_STATUS 0x08 | ||
309 | #define CR_RECOVER (1<<7) | ||
310 | #define CR_PLAYUNDER (1<<6) | ||
311 | #define CR_CODECREADY (1<<5) | ||
312 | #define CR_RAF (1<<4) | ||
313 | #define CR_RECEMPTY (1<<3) | ||
314 | #define CR_RECFULL (1<<2) | ||
315 | #define CR_PLAYHALF (1<<1) | ||
316 | #define CR_PLAYFULL (1<<0) | ||
317 | |||
318 | #define CR_REG_RESETFIFO 0x0C | ||
319 | #define CR_RECRESET (1<<1) | ||
320 | #define CR_PLAYRESET (1<<0) | ||
321 | |||
322 | #define CR_REG_CODEC_ADDR 0x10 | ||
323 | /* UG082 says: | ||
324 | * #define CR_CODEC_ADDR(a) ((a) << 1) | ||
325 | * #define CR_CODEC_READ (1<<0) | ||
326 | * #define CR_CODEC_WRITE (0<<0) | ||
327 | */ | ||
328 | /* RefDesign example says: */ | ||
329 | #define CR_CODEC_ADDR(a) ((a) << 0) | ||
330 | #define CR_CODEC_READ (1<<7) | ||
331 | #define CR_CODEC_WRITE (0<<7) | ||
332 | |||
333 | #define CR_REG_CODEC_DATAREAD 0x14 | ||
334 | #define CR_CODEC_DATAREAD(v) ((v) & 0xFFFF) | ||
335 | |||
336 | #define CR_REG_CODEC_DATAWRITE 0x18 | ||
337 | #define CR_CODEC_DATAWRITE(v) ((v) & 0xFFFF) | ||
338 | |||
339 | #define CR_FIFO_SIZE 32 | ||
340 | |||
341 | struct snd_ml403_ac97cr { | ||
342 | /* lock for access to (controller) registers */ | ||
343 | spinlock_t reg_lock; | ||
344 | /* mutex for the whole sequence of accesses to (controller) registers | ||
345 | * which affect codec registers | ||
346 | */ | ||
347 | struct mutex cdc_mutex; | ||
348 | |||
349 | int irq; /* for playback */ | ||
350 | int enable_irq; /* for playback */ | ||
351 | |||
352 | int capture_irq; | ||
353 | int enable_capture_irq; | ||
354 | |||
355 | struct resource *res_port; | ||
356 | void *port; | ||
357 | |||
358 | struct snd_ac97 *ac97; | ||
359 | int ac97_fake; | ||
360 | #ifdef CODEC_STAT | ||
361 | int ac97_read; | ||
362 | int ac97_write; | ||
363 | #endif | ||
364 | |||
365 | struct platform_device *pfdev; | ||
366 | struct snd_card *card; | ||
367 | struct snd_pcm *pcm; | ||
368 | struct snd_pcm_substream *playback_substream; | ||
369 | struct snd_pcm_substream *capture_substream; | ||
370 | |||
371 | struct snd_pcm_indirect2 ind_rec; /* for playback */ | ||
372 | struct snd_pcm_indirect2 capture_ind2_rec; | ||
373 | }; | ||
374 | |||
375 | static struct snd_pcm_hardware snd_ml403_ac97cr_playback = { | ||
376 | .info = (SNDRV_PCM_INFO_MMAP | | ||
377 | SNDRV_PCM_INFO_INTERLEAVED | | ||
378 | SNDRV_PCM_INFO_MMAP_VALID), | ||
379 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
380 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
381 | SNDRV_PCM_RATE_8000_48000), | ||
382 | .rate_min = 4000, | ||
383 | .rate_max = 48000, | ||
384 | .channels_min = 2, | ||
385 | .channels_max = 2, | ||
386 | .buffer_bytes_max = (128*1024), | ||
387 | .period_bytes_min = CR_FIFO_SIZE/2, | ||
388 | .period_bytes_max = (64*1024), | ||
389 | .periods_min = 2, | ||
390 | .periods_max = (128*1024)/(CR_FIFO_SIZE/2), | ||
391 | .fifo_size = 0, | ||
392 | }; | ||
393 | |||
394 | static struct snd_pcm_hardware snd_ml403_ac97cr_capture = { | ||
395 | .info = (SNDRV_PCM_INFO_MMAP | | ||
396 | SNDRV_PCM_INFO_INTERLEAVED | | ||
397 | SNDRV_PCM_INFO_MMAP_VALID), | ||
398 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
399 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
400 | SNDRV_PCM_RATE_8000_48000), | ||
401 | .rate_min = 4000, | ||
402 | .rate_max = 48000, | ||
403 | .channels_min = 2, | ||
404 | .channels_max = 2, | ||
405 | .buffer_bytes_max = (128*1024), | ||
406 | .period_bytes_min = CR_FIFO_SIZE/2, | ||
407 | .period_bytes_max = (64*1024), | ||
408 | .periods_min = 2, | ||
409 | .periods_max = (128*1024)/(CR_FIFO_SIZE/2), | ||
410 | .fifo_size = 0, | ||
411 | }; | ||
412 | |||
413 | static size_t | ||
414 | snd_ml403_ac97cr_playback_ind2_zero(struct snd_pcm_substream *substream, | ||
415 | struct snd_pcm_indirect2 *rec) | ||
416 | { | ||
417 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
418 | int copied_words = 0; | ||
419 | u32 full = 0; | ||
420 | |||
421 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
422 | |||
423 | spin_lock(&ml403_ac97cr->reg_lock); | ||
424 | while ((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
425 | CR_PLAYFULL)) != CR_PLAYFULL) { | ||
426 | out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), 0); | ||
427 | copied_words++; | ||
428 | } | ||
429 | rec->hw_ready = 0; | ||
430 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
431 | |||
432 | return (size_t) (copied_words * 2); | ||
433 | } | ||
434 | |||
435 | static size_t | ||
436 | snd_ml403_ac97cr_playback_ind2_copy(struct snd_pcm_substream *substream, | ||
437 | struct snd_pcm_indirect2 *rec, | ||
438 | size_t bytes) | ||
439 | { | ||
440 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
441 | u16 *src; | ||
442 | int copied_words = 0; | ||
443 | u32 full = 0; | ||
444 | |||
445 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
446 | src = (u16 *)(substream->runtime->dma_area + rec->sw_data); | ||
447 | |||
448 | spin_lock(&ml403_ac97cr->reg_lock); | ||
449 | while (((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
450 | CR_PLAYFULL)) != CR_PLAYFULL) && (bytes > 1)) { | ||
451 | out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), | ||
452 | CR_PLAYDATA(src[copied_words])); | ||
453 | copied_words++; | ||
454 | bytes = bytes - 2; | ||
455 | } | ||
456 | if (full != CR_PLAYFULL) | ||
457 | rec->hw_ready = 1; | ||
458 | else | ||
459 | rec->hw_ready = 0; | ||
460 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
461 | |||
462 | return (size_t) (copied_words * 2); | ||
463 | } | ||
464 | |||
465 | static size_t | ||
466 | snd_ml403_ac97cr_capture_ind2_null(struct snd_pcm_substream *substream, | ||
467 | struct snd_pcm_indirect2 *rec) | ||
468 | { | ||
469 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
470 | int copied_words = 0; | ||
471 | u32 empty = 0; | ||
472 | |||
473 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
474 | |||
475 | spin_lock(&ml403_ac97cr->reg_lock); | ||
476 | while ((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
477 | CR_RECEMPTY)) != CR_RECEMPTY) { | ||
478 | volatile u32 trash; | ||
479 | |||
480 | trash = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, RECFIFO))); | ||
481 | /* Hmmmm, really necessary? Don't want call to in_be32() | ||
482 | * to be optimised away! | ||
483 | */ | ||
484 | trash++; | ||
485 | copied_words++; | ||
486 | } | ||
487 | rec->hw_ready = 0; | ||
488 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
489 | |||
490 | return (size_t) (copied_words * 2); | ||
491 | } | ||
492 | |||
493 | static size_t | ||
494 | snd_ml403_ac97cr_capture_ind2_copy(struct snd_pcm_substream *substream, | ||
495 | struct snd_pcm_indirect2 *rec, size_t bytes) | ||
496 | { | ||
497 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
498 | u16 *dst; | ||
499 | int copied_words = 0; | ||
500 | u32 empty = 0; | ||
501 | |||
502 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
503 | dst = (u16 *)(substream->runtime->dma_area + rec->sw_data); | ||
504 | |||
505 | spin_lock(&ml403_ac97cr->reg_lock); | ||
506 | while (((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
507 | CR_RECEMPTY)) != CR_RECEMPTY) && (bytes > 1)) { | ||
508 | dst[copied_words] = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, | ||
509 | RECFIFO))); | ||
510 | copied_words++; | ||
511 | bytes = bytes - 2; | ||
512 | } | ||
513 | if (empty != CR_RECEMPTY) | ||
514 | rec->hw_ready = 1; | ||
515 | else | ||
516 | rec->hw_ready = 0; | ||
517 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
518 | |||
519 | return (size_t) (copied_words * 2); | ||
520 | } | ||
521 | |||
522 | static snd_pcm_uframes_t | ||
523 | snd_ml403_ac97cr_pcm_pointer(struct snd_pcm_substream *substream) | ||
524 | { | ||
525 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
526 | struct snd_pcm_indirect2 *ind2_rec = NULL; | ||
527 | |||
528 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
529 | |||
530 | if (substream == ml403_ac97cr->playback_substream) | ||
531 | ind2_rec = &ml403_ac97cr->ind_rec; | ||
532 | if (substream == ml403_ac97cr->capture_substream) | ||
533 | ind2_rec = &ml403_ac97cr->capture_ind2_rec; | ||
534 | |||
535 | if (ind2_rec != NULL) | ||
536 | return snd_pcm_indirect2_pointer(substream, ind2_rec); | ||
537 | return (snd_pcm_uframes_t) 0; | ||
538 | } | ||
539 | |||
540 | static int | ||
541 | snd_ml403_ac97cr_pcm_playback_trigger(struct snd_pcm_substream *substream, | ||
542 | int cmd) | ||
543 | { | ||
544 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
545 | int err = 0; | ||
546 | |||
547 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
548 | |||
549 | switch (cmd) { | ||
550 | case SNDRV_PCM_TRIGGER_START: | ||
551 | PDEBUG(WORK_INFO, "trigger(playback): START\n"); | ||
552 | ml403_ac97cr->ind_rec.hw_ready = 1; | ||
553 | |||
554 | /* clear play FIFO */ | ||
555 | out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_PLAYRESET); | ||
556 | |||
557 | /* enable play irq */ | ||
558 | ml403_ac97cr->enable_irq = 1; | ||
559 | enable_irq(ml403_ac97cr->irq); | ||
560 | break; | ||
561 | case SNDRV_PCM_TRIGGER_STOP: | ||
562 | PDEBUG(WORK_INFO, "trigger(playback): STOP\n"); | ||
563 | ml403_ac97cr->ind_rec.hw_ready = 0; | ||
564 | #ifdef SND_PCM_INDIRECT2_STAT | ||
565 | snd_pcm_indirect2_stat(substream, &ml403_ac97cr->ind_rec); | ||
566 | #endif | ||
567 | /* disable play irq */ | ||
568 | disable_irq_nosync(ml403_ac97cr->irq); | ||
569 | ml403_ac97cr->enable_irq = 0; | ||
570 | break; | ||
571 | default: | ||
572 | err = -EINVAL; | ||
573 | break; | ||
574 | } | ||
575 | PDEBUG(WORK_INFO, "trigger(playback): (done)\n"); | ||
576 | return err; | ||
577 | } | ||
578 | |||
579 | static int | ||
580 | snd_ml403_ac97cr_pcm_capture_trigger(struct snd_pcm_substream *substream, | ||
581 | int cmd) | ||
582 | { | ||
583 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
584 | int err = 0; | ||
585 | |||
586 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
587 | |||
588 | switch (cmd) { | ||
589 | case SNDRV_PCM_TRIGGER_START: | ||
590 | PDEBUG(WORK_INFO, "trigger(capture): START\n"); | ||
591 | ml403_ac97cr->capture_ind2_rec.hw_ready = 0; | ||
592 | |||
593 | /* clear record FIFO */ | ||
594 | out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_RECRESET); | ||
595 | |||
596 | /* enable record irq */ | ||
597 | ml403_ac97cr->enable_capture_irq = 1; | ||
598 | enable_irq(ml403_ac97cr->capture_irq); | ||
599 | break; | ||
600 | case SNDRV_PCM_TRIGGER_STOP: | ||
601 | PDEBUG(WORK_INFO, "trigger(capture): STOP\n"); | ||
602 | ml403_ac97cr->capture_ind2_rec.hw_ready = 0; | ||
603 | #ifdef SND_PCM_INDIRECT2_STAT | ||
604 | snd_pcm_indirect2_stat(substream, | ||
605 | &ml403_ac97cr->capture_ind2_rec); | ||
606 | #endif | ||
607 | /* disable capture irq */ | ||
608 | disable_irq_nosync(ml403_ac97cr->capture_irq); | ||
609 | ml403_ac97cr->enable_capture_irq = 0; | ||
610 | break; | ||
611 | default: | ||
612 | err = -EINVAL; | ||
613 | break; | ||
614 | } | ||
615 | PDEBUG(WORK_INFO, "trigger(capture): (done)\n"); | ||
616 | return err; | ||
617 | } | ||
618 | |||
619 | static int | ||
620 | snd_ml403_ac97cr_pcm_playback_prepare(struct snd_pcm_substream *substream) | ||
621 | { | ||
622 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
623 | struct snd_pcm_runtime *runtime; | ||
624 | |||
625 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
626 | runtime = substream->runtime; | ||
627 | |||
628 | PDEBUG(WORK_INFO, | ||
629 | "prepare(): period_bytes=%d, minperiod_bytes=%d\n", | ||
630 | snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2); | ||
631 | |||
632 | /* set sampling rate */ | ||
633 | snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_FRONT_DAC_RATE, | ||
634 | runtime->rate); | ||
635 | PDEBUG(WORK_INFO, "prepare(): rate=%d\n", runtime->rate); | ||
636 | |||
637 | /* init struct for intermediate buffer */ | ||
638 | memset(&ml403_ac97cr->ind_rec, 0, | ||
639 | sizeof(struct snd_pcm_indirect2)); | ||
640 | ml403_ac97cr->ind_rec.hw_buffer_size = CR_FIFO_SIZE; | ||
641 | ml403_ac97cr->ind_rec.sw_buffer_size = | ||
642 | snd_pcm_lib_buffer_bytes(substream); | ||
643 | ml403_ac97cr->ind_rec.min_periods = -1; | ||
644 | ml403_ac97cr->ind_rec.min_multiple = | ||
645 | snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2); | ||
646 | PDEBUG(WORK_INFO, "prepare(): hw_buffer_size=%d, " | ||
647 | "sw_buffer_size=%d, min_multiple=%d\n", | ||
648 | CR_FIFO_SIZE, ml403_ac97cr->ind_rec.sw_buffer_size, | ||
649 | ml403_ac97cr->ind_rec.min_multiple); | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int | ||
654 | snd_ml403_ac97cr_pcm_capture_prepare(struct snd_pcm_substream *substream) | ||
655 | { | ||
656 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
657 | struct snd_pcm_runtime *runtime; | ||
658 | |||
659 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
660 | runtime = substream->runtime; | ||
661 | |||
662 | PDEBUG(WORK_INFO, | ||
663 | "prepare(capture): period_bytes=%d, minperiod_bytes=%d\n", | ||
664 | snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2); | ||
665 | |||
666 | /* set sampling rate */ | ||
667 | snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_LR_ADC_RATE, | ||
668 | runtime->rate); | ||
669 | PDEBUG(WORK_INFO, "prepare(capture): rate=%d\n", runtime->rate); | ||
670 | |||
671 | /* init struct for intermediate buffer */ | ||
672 | memset(&ml403_ac97cr->capture_ind2_rec, 0, | ||
673 | sizeof(struct snd_pcm_indirect2)); | ||
674 | ml403_ac97cr->capture_ind2_rec.hw_buffer_size = CR_FIFO_SIZE; | ||
675 | ml403_ac97cr->capture_ind2_rec.sw_buffer_size = | ||
676 | snd_pcm_lib_buffer_bytes(substream); | ||
677 | ml403_ac97cr->capture_ind2_rec.min_multiple = | ||
678 | snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2); | ||
679 | PDEBUG(WORK_INFO, "prepare(capture): hw_buffer_size=%d, " | ||
680 | "sw_buffer_size=%d, min_multiple=%d\n", CR_FIFO_SIZE, | ||
681 | ml403_ac97cr->capture_ind2_rec.sw_buffer_size, | ||
682 | ml403_ac97cr->capture_ind2_rec.min_multiple); | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static int snd_ml403_ac97cr_hw_free(struct snd_pcm_substream *substream) | ||
687 | { | ||
688 | PDEBUG(WORK_INFO, "hw_free()\n"); | ||
689 | return snd_pcm_lib_free_pages(substream); | ||
690 | } | ||
691 | |||
692 | static int | ||
693 | snd_ml403_ac97cr_hw_params(struct snd_pcm_substream *substream, | ||
694 | struct snd_pcm_hw_params *hw_params) | ||
695 | { | ||
696 | PDEBUG(WORK_INFO, "hw_params(): desired buffer bytes=%d, desired " | ||
697 | "period bytes=%d\n", | ||
698 | params_buffer_bytes(hw_params), params_period_bytes(hw_params)); | ||
699 | return snd_pcm_lib_malloc_pages(substream, | ||
700 | params_buffer_bytes(hw_params)); | ||
701 | } | ||
702 | |||
703 | static int snd_ml403_ac97cr_playback_open(struct snd_pcm_substream *substream) | ||
704 | { | ||
705 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
706 | struct snd_pcm_runtime *runtime; | ||
707 | |||
708 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
709 | runtime = substream->runtime; | ||
710 | |||
711 | PDEBUG(WORK_INFO, "open(playback)\n"); | ||
712 | ml403_ac97cr->playback_substream = substream; | ||
713 | runtime->hw = snd_ml403_ac97cr_playback; | ||
714 | |||
715 | snd_pcm_hw_constraint_step(runtime, 0, | ||
716 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
717 | CR_FIFO_SIZE / 2); | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static int snd_ml403_ac97cr_capture_open(struct snd_pcm_substream *substream) | ||
722 | { | ||
723 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
724 | struct snd_pcm_runtime *runtime; | ||
725 | |||
726 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
727 | runtime = substream->runtime; | ||
728 | |||
729 | PDEBUG(WORK_INFO, "open(capture)\n"); | ||
730 | ml403_ac97cr->capture_substream = substream; | ||
731 | runtime->hw = snd_ml403_ac97cr_capture; | ||
732 | |||
733 | snd_pcm_hw_constraint_step(runtime, 0, | ||
734 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
735 | CR_FIFO_SIZE / 2); | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static int snd_ml403_ac97cr_playback_close(struct snd_pcm_substream *substream) | ||
740 | { | ||
741 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
742 | |||
743 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
744 | |||
745 | PDEBUG(WORK_INFO, "close(playback)\n"); | ||
746 | ml403_ac97cr->playback_substream = NULL; | ||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static int snd_ml403_ac97cr_capture_close(struct snd_pcm_substream *substream) | ||
751 | { | ||
752 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
753 | |||
754 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
755 | |||
756 | PDEBUG(WORK_INFO, "close(capture)\n"); | ||
757 | ml403_ac97cr->capture_substream = NULL; | ||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | static struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = { | ||
762 | .open = snd_ml403_ac97cr_playback_open, | ||
763 | .close = snd_ml403_ac97cr_playback_close, | ||
764 | .ioctl = snd_pcm_lib_ioctl, | ||
765 | .hw_params = snd_ml403_ac97cr_hw_params, | ||
766 | .hw_free = snd_ml403_ac97cr_hw_free, | ||
767 | .prepare = snd_ml403_ac97cr_pcm_playback_prepare, | ||
768 | .trigger = snd_ml403_ac97cr_pcm_playback_trigger, | ||
769 | .pointer = snd_ml403_ac97cr_pcm_pointer, | ||
770 | }; | ||
771 | |||
772 | static struct snd_pcm_ops snd_ml403_ac97cr_capture_ops = { | ||
773 | .open = snd_ml403_ac97cr_capture_open, | ||
774 | .close = snd_ml403_ac97cr_capture_close, | ||
775 | .ioctl = snd_pcm_lib_ioctl, | ||
776 | .hw_params = snd_ml403_ac97cr_hw_params, | ||
777 | .hw_free = snd_ml403_ac97cr_hw_free, | ||
778 | .prepare = snd_ml403_ac97cr_pcm_capture_prepare, | ||
779 | .trigger = snd_ml403_ac97cr_pcm_capture_trigger, | ||
780 | .pointer = snd_ml403_ac97cr_pcm_pointer, | ||
781 | }; | ||
782 | |||
783 | static irqreturn_t snd_ml403_ac97cr_irq(int irq, void *dev_id) | ||
784 | { | ||
785 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
786 | struct platform_device *pfdev; | ||
787 | int cmp_irq; | ||
788 | |||
789 | ml403_ac97cr = (struct snd_ml403_ac97cr *)dev_id; | ||
790 | if (ml403_ac97cr == NULL) | ||
791 | return IRQ_NONE; | ||
792 | |||
793 | pfdev = ml403_ac97cr->pfdev; | ||
794 | |||
795 | /* playback interrupt */ | ||
796 | cmp_irq = platform_get_irq(pfdev, 0); | ||
797 | if (irq == cmp_irq) { | ||
798 | if (ml403_ac97cr->enable_irq) | ||
799 | snd_pcm_indirect2_playback_interrupt( | ||
800 | ml403_ac97cr->playback_substream, | ||
801 | &ml403_ac97cr->ind_rec, | ||
802 | snd_ml403_ac97cr_playback_ind2_copy, | ||
803 | snd_ml403_ac97cr_playback_ind2_zero); | ||
804 | else | ||
805 | goto __disable_irq; | ||
806 | } else { | ||
807 | /* record interrupt */ | ||
808 | cmp_irq = platform_get_irq(pfdev, 1); | ||
809 | if (irq == cmp_irq) { | ||
810 | if (ml403_ac97cr->enable_capture_irq) | ||
811 | snd_pcm_indirect2_capture_interrupt( | ||
812 | ml403_ac97cr->capture_substream, | ||
813 | &ml403_ac97cr->capture_ind2_rec, | ||
814 | snd_ml403_ac97cr_capture_ind2_copy, | ||
815 | snd_ml403_ac97cr_capture_ind2_null); | ||
816 | else | ||
817 | goto __disable_irq; | ||
818 | } else | ||
819 | return IRQ_NONE; | ||
820 | } | ||
821 | return IRQ_HANDLED; | ||
822 | |||
823 | __disable_irq: | ||
824 | PDEBUG(INIT_INFO, "irq(): irq %d is meant to be disabled! So, now try " | ||
825 | "to disable it _really_!\n", irq); | ||
826 | disable_irq_nosync(irq); | ||
827 | return IRQ_HANDLED; | ||
828 | } | ||
829 | |||
830 | static unsigned short | ||
831 | snd_ml403_ac97cr_codec_read(struct snd_ac97 *ac97, unsigned short reg) | ||
832 | { | ||
833 | struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | ||
834 | #ifdef CODEC_STAT | ||
835 | u32 stat; | ||
836 | u32 rafaccess = 0; | ||
837 | #endif | ||
838 | unsigned long end_time; | ||
839 | u16 value = 0; | ||
840 | |||
841 | if (!LM4550_RF_OK(reg)) { | ||
842 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
843 | "access to unknown/unused codec register 0x%x " | ||
844 | "ignored!\n", reg); | ||
845 | return 0; | ||
846 | } | ||
847 | /* check if we can fake/answer this access from our shadow register */ | ||
848 | if ((lm4550_regfile[reg / 2].flag & | ||
849 | (LM4550_REG_DONEREAD | LM4550_REG_ALLFAKE)) && | ||
850 | !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) { | ||
851 | if (lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEREAD) { | ||
852 | PDEBUG(CODEC_FAKE, "codec_read(): faking read from " | ||
853 | "reg=0x%x, val=0x%x / %d\n", | ||
854 | reg, lm4550_regfile[reg / 2].def, | ||
855 | lm4550_regfile[reg / 2].def); | ||
856 | return lm4550_regfile[reg / 2].def; | ||
857 | } else if ((lm4550_regfile[reg / 2].flag & | ||
858 | LM4550_REG_FAKEPROBE) && | ||
859 | ml403_ac97cr->ac97_fake) { | ||
860 | PDEBUG(CODEC_FAKE, "codec_read(): faking read from " | ||
861 | "reg=0x%x, val=0x%x / %d (probe)\n", | ||
862 | reg, lm4550_regfile[reg / 2].value, | ||
863 | lm4550_regfile[reg / 2].value); | ||
864 | return lm4550_regfile[reg / 2].value; | ||
865 | } else { | ||
866 | #ifdef CODEC_STAT | ||
867 | PDEBUG(CODEC_FAKE, "codec_read(): read access " | ||
868 | "answered by shadow register 0x%x (value=0x%x " | ||
869 | "/ %d) (cw=%d cr=%d)\n", | ||
870 | reg, lm4550_regfile[reg / 2].value, | ||
871 | lm4550_regfile[reg / 2].value, | ||
872 | ml403_ac97cr->ac97_write, | ||
873 | ml403_ac97cr->ac97_read); | ||
874 | #else | ||
875 | PDEBUG(CODEC_FAKE, "codec_read(): read access " | ||
876 | "answered by shadow register 0x%x (value=0x%x " | ||
877 | "/ %d)\n", | ||
878 | reg, lm4550_regfile[reg / 2].value, | ||
879 | lm4550_regfile[reg / 2].value); | ||
880 | #endif | ||
881 | return lm4550_regfile[reg / 2].value; | ||
882 | } | ||
883 | } | ||
884 | /* if we are here, we _have_ to access the codec really, no faking */ | ||
885 | if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0) | ||
886 | return 0; | ||
887 | #ifdef CODEC_STAT | ||
888 | ml403_ac97cr->ac97_read++; | ||
889 | #endif | ||
890 | spin_lock(&ml403_ac97cr->reg_lock); | ||
891 | out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR), | ||
892 | CR_CODEC_ADDR(reg) | CR_CODEC_READ); | ||
893 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
894 | end_time = jiffies + (HZ / CODEC_TIMEOUT_AFTER_READ); | ||
895 | do { | ||
896 | spin_lock(&ml403_ac97cr->reg_lock); | ||
897 | #ifdef CODEC_STAT | ||
898 | rafaccess++; | ||
899 | stat = in_be32(CR_REG(ml403_ac97cr, STATUS)); | ||
900 | if ((stat & CR_RAF) == CR_RAF) { | ||
901 | value = CR_CODEC_DATAREAD( | ||
902 | in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | ||
903 | PDEBUG(CODEC_SUCCESS, "codec_read(): (done) reg=0x%x, " | ||
904 | "value=0x%x / %d (STATUS=0x%x)\n", | ||
905 | reg, value, value, stat); | ||
906 | #else | ||
907 | if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
908 | CR_RAF) == CR_RAF) { | ||
909 | value = CR_CODEC_DATAREAD( | ||
910 | in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | ||
911 | PDEBUG(CODEC_SUCCESS, "codec_read(): (done) " | ||
912 | "reg=0x%x, value=0x%x / %d\n", | ||
913 | reg, value, value); | ||
914 | #endif | ||
915 | lm4550_regfile[reg / 2].value = value; | ||
916 | lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | ||
917 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
918 | mutex_unlock(&ml403_ac97cr->cdc_mutex); | ||
919 | return value; | ||
920 | } | ||
921 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
922 | schedule_timeout_uninterruptible(1); | ||
923 | } while (time_after(end_time, jiffies)); | ||
924 | /* read the DATAREAD register anyway, see comment below */ | ||
925 | spin_lock(&ml403_ac97cr->reg_lock); | ||
926 | value = | ||
927 | CR_CODEC_DATAREAD(in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | ||
928 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
929 | #ifdef CODEC_STAT | ||
930 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
931 | "timeout while codec read! " | ||
932 | "(reg=0x%x, last STATUS=0x%x, DATAREAD=0x%x / %d, %d) " | ||
933 | "(cw=%d, cr=%d)\n", | ||
934 | reg, stat, value, value, rafaccess, | ||
935 | ml403_ac97cr->ac97_write, ml403_ac97cr->ac97_read); | ||
936 | #else | ||
937 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
938 | "timeout while codec read! " | ||
939 | "(reg=0x%x, DATAREAD=0x%x / %d)\n", | ||
940 | reg, value, value); | ||
941 | #endif | ||
942 | /* BUG: This is PURE speculation! But after _most_ read timeouts the | ||
943 | * value in the register is ok! | ||
944 | */ | ||
945 | lm4550_regfile[reg / 2].value = value; | ||
946 | lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | ||
947 | mutex_unlock(&ml403_ac97cr->cdc_mutex); | ||
948 | return value; | ||
949 | } | ||
950 | |||
951 | static void | ||
952 | snd_ml403_ac97cr_codec_write(struct snd_ac97 *ac97, unsigned short reg, | ||
953 | unsigned short val) | ||
954 | { | ||
955 | struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | ||
956 | |||
957 | #ifdef CODEC_STAT | ||
958 | u32 stat; | ||
959 | u32 rafaccess = 0; | ||
960 | #endif | ||
961 | #ifdef CODEC_WRITE_CHECK_RAF | ||
962 | unsigned long end_time; | ||
963 | #endif | ||
964 | |||
965 | if (!LM4550_RF_OK(reg)) { | ||
966 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
967 | "access to unknown/unused codec register 0x%x " | ||
968 | "ignored!\n", reg); | ||
969 | return; | ||
970 | } | ||
971 | if (lm4550_regfile[reg / 2].flag & LM4550_REG_READONLY) { | ||
972 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
973 | "write access to read only codec register 0x%x " | ||
974 | "ignored!\n", reg); | ||
975 | return; | ||
976 | } | ||
977 | if ((val & lm4550_regfile[reg / 2].wmask) != val) { | ||
978 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
979 | "write access to codec register 0x%x " | ||
980 | "with bad value 0x%x / %d!\n", | ||
981 | reg, val, val); | ||
982 | val = val & lm4550_regfile[reg / 2].wmask; | ||
983 | } | ||
984 | if (((lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEPROBE) && | ||
985 | ml403_ac97cr->ac97_fake) && | ||
986 | !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) { | ||
987 | PDEBUG(CODEC_FAKE, "codec_write(): faking write to reg=0x%x, " | ||
988 | "val=0x%x / %d\n", reg, val, val); | ||
989 | lm4550_regfile[reg / 2].value = (val & | ||
990 | lm4550_regfile[reg / 2].wmask); | ||
991 | return; | ||
992 | } | ||
993 | if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0) | ||
994 | return; | ||
995 | #ifdef CODEC_STAT | ||
996 | ml403_ac97cr->ac97_write++; | ||
997 | #endif | ||
998 | spin_lock(&ml403_ac97cr->reg_lock); | ||
999 | out_be32(CR_REG(ml403_ac97cr, CODEC_DATAWRITE), | ||
1000 | CR_CODEC_DATAWRITE(val)); | ||
1001 | out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR), | ||
1002 | CR_CODEC_ADDR(reg) | CR_CODEC_WRITE); | ||
1003 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
1004 | #ifdef CODEC_WRITE_CHECK_RAF | ||
1005 | /* check CR_CODEC_RAF bit to see if write access to register is done; | ||
1006 | * loop until bit is set or timeout happens | ||
1007 | */ | ||
1008 | end_time = jiffies + HZ / CODEC_TIMEOUT_AFTER_WRITE; | ||
1009 | do { | ||
1010 | spin_lock(&ml403_ac97cr->reg_lock); | ||
1011 | #ifdef CODEC_STAT | ||
1012 | rafaccess++; | ||
1013 | stat = in_be32(CR_REG(ml403_ac97cr, STATUS)) | ||
1014 | if ((stat & CR_RAF) == CR_RAF) { | ||
1015 | #else | ||
1016 | if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
1017 | CR_RAF) == CR_RAF) { | ||
1018 | #endif | ||
1019 | PDEBUG(CODEC_SUCCESS, "codec_write(): (done) " | ||
1020 | "reg=0x%x, value=%d / 0x%x\n", | ||
1021 | reg, val, val); | ||
1022 | if (!(lm4550_regfile[reg / 2].flag & | ||
1023 | LM4550_REG_NOSHADOW) && | ||
1024 | !(lm4550_regfile[reg / 2].flag & | ||
1025 | LM4550_REG_NOSAVE)) | ||
1026 | lm4550_regfile[reg / 2].value = val; | ||
1027 | lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | ||
1028 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
1029 | mutex_unlock(&ml403_ac97cr->cdc_mutex); | ||
1030 | return; | ||
1031 | } | ||
1032 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
1033 | schedule_timeout_uninterruptible(1); | ||
1034 | } while (time_after(end_time, jiffies)); | ||
1035 | #ifdef CODEC_STAT | ||
1036 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
1037 | "timeout while codec write " | ||
1038 | "(reg=0x%x, val=0x%x / %d, last STATUS=0x%x, %d) " | ||
1039 | "(cw=%d, cr=%d)\n", | ||
1040 | reg, val, val, stat, rafaccess, ml403_ac97cr->ac97_write, | ||
1041 | ml403_ac97cr->ac97_read); | ||
1042 | #else | ||
1043 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
1044 | "timeout while codec write (reg=0x%x, val=0x%x / %d)\n", | ||
1045 | reg, val, val); | ||
1046 | #endif | ||
1047 | #else /* CODEC_WRITE_CHECK_RAF */ | ||
1048 | #if CODEC_WAIT_AFTER_WRITE > 0 | ||
1049 | /* officially, in AC97 spec there is no possibility for a AC97 | ||
1050 | * controller to determine, if write access is done or not - so: How | ||
1051 | * is Xilinx able to provide a RAF bit for write access? | ||
1052 | * => very strange, thus just don't check RAF bit (compare with | ||
1053 | * Xilinx's example app in EDK 8.1i) and wait | ||
1054 | */ | ||
1055 | schedule_timeout_uninterruptible(HZ / CODEC_WAIT_AFTER_WRITE); | ||
1056 | #endif | ||
1057 | PDEBUG(CODEC_SUCCESS, "codec_write(): (done) " | ||
1058 | "reg=0x%x, value=%d / 0x%x (no RAF check)\n", | ||
1059 | reg, val, val); | ||
1060 | #endif | ||
1061 | mutex_unlock(&ml403_ac97cr->cdc_mutex); | ||
1062 | return; | ||
1063 | } | ||
1064 | |||
1065 | static int __devinit | ||
1066 | snd_ml403_ac97cr_chip_init(struct snd_ml403_ac97cr *ml403_ac97cr) | ||
1067 | { | ||
1068 | unsigned long end_time; | ||
1069 | PDEBUG(INIT_INFO, "chip_init():\n"); | ||
1070 | end_time = jiffies + HZ / CODEC_TIMEOUT_ON_INIT; | ||
1071 | do { | ||
1072 | if (in_be32(CR_REG(ml403_ac97cr, STATUS)) & CR_CODECREADY) { | ||
1073 | /* clear both hardware FIFOs */ | ||
1074 | out_be32(CR_REG(ml403_ac97cr, RESETFIFO), | ||
1075 | CR_RECRESET | CR_PLAYRESET); | ||
1076 | PDEBUG(INIT_INFO, "chip_init(): (done)\n"); | ||
1077 | return 0; | ||
1078 | } | ||
1079 | schedule_timeout_uninterruptible(1); | ||
1080 | } while (time_after(end_time, jiffies)); | ||
1081 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | ||
1082 | "timeout while waiting for codec, " | ||
1083 | "not ready!\n"); | ||
1084 | return -EBUSY; | ||
1085 | } | ||
1086 | |||
1087 | static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr) | ||
1088 | { | ||
1089 | PDEBUG(INIT_INFO, "free():\n"); | ||
1090 | /* irq release */ | ||
1091 | if (ml403_ac97cr->irq >= 0) | ||
1092 | free_irq(ml403_ac97cr->irq, ml403_ac97cr); | ||
1093 | if (ml403_ac97cr->capture_irq >= 0) | ||
1094 | free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr); | ||
1095 | /* give back "port" */ | ||
1096 | if (ml403_ac97cr->port != NULL) | ||
1097 | iounmap(ml403_ac97cr->port); | ||
1098 | kfree(ml403_ac97cr); | ||
1099 | PDEBUG(INIT_INFO, "free(): (done)\n"); | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static int snd_ml403_ac97cr_dev_free(struct snd_device *snddev) | ||
1104 | { | ||
1105 | struct snd_ml403_ac97cr *ml403_ac97cr = snddev->device_data; | ||
1106 | PDEBUG(INIT_INFO, "dev_free():\n"); | ||
1107 | return snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1108 | } | ||
1109 | |||
1110 | static int __devinit | ||
1111 | snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, | ||
1112 | struct snd_ml403_ac97cr **rml403_ac97cr) | ||
1113 | { | ||
1114 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
1115 | int err; | ||
1116 | static struct snd_device_ops ops = { | ||
1117 | .dev_free = snd_ml403_ac97cr_dev_free, | ||
1118 | }; | ||
1119 | struct resource *resource; | ||
1120 | int irq; | ||
1121 | |||
1122 | *rml403_ac97cr = NULL; | ||
1123 | ml403_ac97cr = kzalloc(sizeof(*ml403_ac97cr), GFP_KERNEL); | ||
1124 | if (ml403_ac97cr == NULL) | ||
1125 | return -ENOMEM; | ||
1126 | spin_lock_init(&ml403_ac97cr->reg_lock); | ||
1127 | mutex_init(&ml403_ac97cr->cdc_mutex); | ||
1128 | ml403_ac97cr->card = card; | ||
1129 | ml403_ac97cr->pfdev = pfdev; | ||
1130 | ml403_ac97cr->irq = -1; | ||
1131 | ml403_ac97cr->enable_irq = 0; | ||
1132 | ml403_ac97cr->capture_irq = -1; | ||
1133 | ml403_ac97cr->enable_capture_irq = 0; | ||
1134 | ml403_ac97cr->port = NULL; | ||
1135 | ml403_ac97cr->res_port = NULL; | ||
1136 | |||
1137 | PDEBUG(INIT_INFO, "Trying to reserve resources now ...\n"); | ||
1138 | resource = platform_get_resource(pfdev, IORESOURCE_MEM, 0); | ||
1139 | /* get "port" */ | ||
1140 | ml403_ac97cr->port = ioremap_nocache(resource->start, | ||
1141 | (resource->end) - | ||
1142 | (resource->start) + 1); | ||
1143 | if (ml403_ac97cr->port == NULL) { | ||
1144 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | ||
1145 | "unable to remap memory region (%x to %x)\n", | ||
1146 | resource->start, resource->end); | ||
1147 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1148 | return -EBUSY; | ||
1149 | } | ||
1150 | snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | ||
1151 | "remap controller memory region to " | ||
1152 | "0x%x done\n", (unsigned int)ml403_ac97cr->port); | ||
1153 | /* get irq */ | ||
1154 | irq = platform_get_irq(pfdev, 0); | ||
1155 | if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, | ||
1156 | pfdev->dev.bus_id, (void *)ml403_ac97cr)) { | ||
1157 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | ||
1158 | "unable to grab IRQ %d\n", | ||
1159 | irq); | ||
1160 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1161 | return -EBUSY; | ||
1162 | } | ||
1163 | ml403_ac97cr->irq = irq; | ||
1164 | snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | ||
1165 | "request (playback) irq %d done\n", | ||
1166 | ml403_ac97cr->irq); | ||
1167 | irq = platform_get_irq(pfdev, 1); | ||
1168 | if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, | ||
1169 | pfdev->dev.bus_id, (void *)ml403_ac97cr)) { | ||
1170 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | ||
1171 | "unable to grab IRQ %d\n", | ||
1172 | irq); | ||
1173 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1174 | return -EBUSY; | ||
1175 | } | ||
1176 | ml403_ac97cr->capture_irq = irq; | ||
1177 | snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | ||
1178 | "request (capture) irq %d done\n", | ||
1179 | ml403_ac97cr->capture_irq); | ||
1180 | |||
1181 | err = snd_ml403_ac97cr_chip_init(ml403_ac97cr); | ||
1182 | if (err < 0) { | ||
1183 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1184 | return err; | ||
1185 | } | ||
1186 | |||
1187 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ml403_ac97cr, &ops); | ||
1188 | if (err < 0) { | ||
1189 | PDEBUG(INIT_FAILURE, "probe(): snd_device_new() failed!\n"); | ||
1190 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1191 | return err; | ||
1192 | } | ||
1193 | |||
1194 | snd_card_set_dev(card, &pfdev->dev); | ||
1195 | |||
1196 | *rml403_ac97cr = ml403_ac97cr; | ||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | static void snd_ml403_ac97cr_mixer_free(struct snd_ac97 *ac97) | ||
1201 | { | ||
1202 | struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | ||
1203 | PDEBUG(INIT_INFO, "mixer_free():\n"); | ||
1204 | ml403_ac97cr->ac97 = NULL; | ||
1205 | PDEBUG(INIT_INFO, "mixer_free(): (done)\n"); | ||
1206 | } | ||
1207 | |||
1208 | static int __devinit | ||
1209 | snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr) | ||
1210 | { | ||
1211 | struct snd_ac97_bus *bus; | ||
1212 | struct snd_ac97_template ac97; | ||
1213 | int err; | ||
1214 | static struct snd_ac97_bus_ops ops = { | ||
1215 | .write = snd_ml403_ac97cr_codec_write, | ||
1216 | .read = snd_ml403_ac97cr_codec_read, | ||
1217 | }; | ||
1218 | PDEBUG(INIT_INFO, "mixer():\n"); | ||
1219 | err = snd_ac97_bus(ml403_ac97cr->card, 0, &ops, NULL, &bus); | ||
1220 | if (err < 0) | ||
1221 | return err; | ||
1222 | |||
1223 | memset(&ac97, 0, sizeof(ac97)); | ||
1224 | ml403_ac97cr->ac97_fake = 1; | ||
1225 | lm4550_regfile_init(); | ||
1226 | #ifdef CODEC_STAT | ||
1227 | ml403_ac97cr->ac97_read = 0; | ||
1228 | ml403_ac97cr->ac97_write = 0; | ||
1229 | #endif | ||
1230 | ac97.private_data = ml403_ac97cr; | ||
1231 | ac97.private_free = snd_ml403_ac97cr_mixer_free; | ||
1232 | ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM | | ||
1233 | AC97_SCAP_NO_SPDIF; | ||
1234 | err = snd_ac97_mixer(bus, &ac97, &ml403_ac97cr->ac97); | ||
1235 | ml403_ac97cr->ac97_fake = 0; | ||
1236 | lm4550_regfile_write_values_after_init(ml403_ac97cr->ac97); | ||
1237 | PDEBUG(INIT_INFO, "mixer(): (done) snd_ac97_mixer()=%d\n", err); | ||
1238 | return err; | ||
1239 | } | ||
1240 | |||
1241 | static int __devinit | ||
1242 | snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, | ||
1243 | struct snd_pcm **rpcm) | ||
1244 | { | ||
1245 | struct snd_pcm *pcm; | ||
1246 | int err; | ||
1247 | |||
1248 | if (rpcm) | ||
1249 | *rpcm = NULL; | ||
1250 | err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1, | ||
1251 | &pcm); | ||
1252 | if (err < 0) | ||
1253 | return err; | ||
1254 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
1255 | &snd_ml403_ac97cr_playback_ops); | ||
1256 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
1257 | &snd_ml403_ac97cr_capture_ops); | ||
1258 | pcm->private_data = ml403_ac97cr; | ||
1259 | pcm->info_flags = 0; | ||
1260 | strcpy(pcm->name, "ML403AC97CR DAC/ADC"); | ||
1261 | ml403_ac97cr->pcm = pcm; | ||
1262 | |||
1263 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | ||
1264 | snd_dma_continuous_data(GFP_KERNEL), | ||
1265 | 64 * 1024, | ||
1266 | 128 * 1024); | ||
1267 | if (rpcm) | ||
1268 | *rpcm = pcm; | ||
1269 | return 0; | ||
1270 | } | ||
1271 | |||
1272 | static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev) | ||
1273 | { | ||
1274 | struct snd_card *card; | ||
1275 | struct snd_ml403_ac97cr *ml403_ac97cr = NULL; | ||
1276 | int err; | ||
1277 | int dev = pfdev->id; | ||
1278 | |||
1279 | if (dev >= SNDRV_CARDS) | ||
1280 | return -ENODEV; | ||
1281 | if (!enable[dev]) | ||
1282 | return -ENOENT; | ||
1283 | |||
1284 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
1285 | if (card == NULL) | ||
1286 | return -ENOMEM; | ||
1287 | err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr); | ||
1288 | if (err < 0) { | ||
1289 | PDEBUG(INIT_FAILURE, "probe(): create failed!\n"); | ||
1290 | snd_card_free(card); | ||
1291 | return err; | ||
1292 | } | ||
1293 | PDEBUG(INIT_INFO, "probe(): create done\n"); | ||
1294 | card->private_data = ml403_ac97cr; | ||
1295 | err = snd_ml403_ac97cr_mixer(ml403_ac97cr); | ||
1296 | if (err < 0) { | ||
1297 | snd_card_free(card); | ||
1298 | return err; | ||
1299 | } | ||
1300 | PDEBUG(INIT_INFO, "probe(): mixer done\n"); | ||
1301 | err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL); | ||
1302 | if (err < 0) { | ||
1303 | snd_card_free(card); | ||
1304 | return err; | ||
1305 | } | ||
1306 | PDEBUG(INIT_INFO, "probe(): PCM done\n"); | ||
1307 | strcpy(card->driver, SND_ML403_AC97CR_DRIVER); | ||
1308 | strcpy(card->shortname, "ML403 AC97 Controller Reference"); | ||
1309 | sprintf(card->longname, "%s %s at 0x%lx, irq %i & %i, device %i", | ||
1310 | card->shortname, card->driver, | ||
1311 | (unsigned long)ml403_ac97cr->port, ml403_ac97cr->irq, | ||
1312 | ml403_ac97cr->capture_irq, dev + 1); | ||
1313 | |||
1314 | snd_card_set_dev(card, &pfdev->dev); | ||
1315 | |||
1316 | err = snd_card_register(card); | ||
1317 | if (err < 0) { | ||
1318 | snd_card_free(card); | ||
1319 | return err; | ||
1320 | } | ||
1321 | platform_set_drvdata(pfdev, card); | ||
1322 | PDEBUG(INIT_INFO, "probe(): (done)\n"); | ||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1326 | static int snd_ml403_ac97cr_remove(struct platform_device *pfdev) | ||
1327 | { | ||
1328 | snd_card_free(platform_get_drvdata(pfdev)); | ||
1329 | platform_set_drvdata(pfdev, NULL); | ||
1330 | return 0; | ||
1331 | } | ||
1332 | |||
1333 | static struct platform_driver snd_ml403_ac97cr_driver = { | ||
1334 | .probe = snd_ml403_ac97cr_probe, | ||
1335 | .remove = snd_ml403_ac97cr_remove, | ||
1336 | .driver = { | ||
1337 | .name = SND_ML403_AC97CR_DRIVER, | ||
1338 | }, | ||
1339 | }; | ||
1340 | |||
1341 | static int __init alsa_card_ml403_ac97cr_init(void) | ||
1342 | { | ||
1343 | return platform_driver_register(&snd_ml403_ac97cr_driver); | ||
1344 | } | ||
1345 | |||
1346 | static void __exit alsa_card_ml403_ac97cr_exit(void) | ||
1347 | { | ||
1348 | platform_driver_unregister(&snd_ml403_ac97cr_driver); | ||
1349 | } | ||
1350 | |||
1351 | module_init(alsa_card_ml403_ac97cr_init) | ||
1352 | module_exit(alsa_card_ml403_ac97cr_exit) | ||
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 1fc95dadde1d..5b996f3faba5 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/pnp.h> | 24 | #include <linux/pnp.h> |
26 | #include <linux/err.h> | 25 | #include <linux/err.h> |
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index b57f2d5a1c9d..5993864acbd3 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <sound/driver.h> | ||
32 | #include <asm/io.h> | 31 | #include <asm/io.h> |
33 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
34 | #include <linux/init.h> | 33 | #include <linux/init.h> |
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 40eb026c86ed..b5e1a71bb64b 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c | |||
@@ -50,7 +50,6 @@ | |||
50 | * | 50 | * |
51 | */ | 51 | */ |
52 | 52 | ||
53 | #include <sound/driver.h> | ||
54 | #include <linux/init.h> | 53 | #include <linux/init.h> |
55 | #include <linux/interrupt.h> | 54 | #include <linux/interrupt.h> |
56 | #include <linux/err.h> | 55 | #include <linux/err.h> |
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index dcc90f995294..87ba1ddc0115 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
24 | #include <linux/parport.h> | 23 | #include <linux/parport.h> |
@@ -461,13 +460,14 @@ static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl, | |||
461 | { | 460 | { |
462 | struct mts64 *mts = snd_kcontrol_chip(kctl); | 461 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
463 | int changed = 0; | 462 | int changed = 0; |
463 | int val = !!uctl->value.integer.value[0]; | ||
464 | 464 | ||
465 | spin_lock_irq(&mts->lock); | 465 | spin_lock_irq(&mts->lock); |
466 | if (mts->smpte_switch == uctl->value.integer.value[0]) | 466 | if (mts->smpte_switch == val) |
467 | goto __out; | 467 | goto __out; |
468 | 468 | ||
469 | changed = 1; | 469 | changed = 1; |
470 | mts->smpte_switch = uctl->value.integer.value[0]; | 470 | mts->smpte_switch = val; |
471 | if (mts->smpte_switch) { | 471 | if (mts->smpte_switch) { |
472 | mts64_smpte_start(mts->pardev->port, | 472 | mts64_smpte_start(mts->pardev->port, |
473 | mts->time[0], mts->time[1], | 473 | mts->time[0], mts->time[1], |
@@ -541,12 +541,13 @@ static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl, | |||
541 | { | 541 | { |
542 | struct mts64 *mts = snd_kcontrol_chip(kctl); | 542 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
543 | int idx = kctl->private_value; | 543 | int idx = kctl->private_value; |
544 | unsigned int time = uctl->value.integer.value[0] % 60; | ||
544 | int changed = 0; | 545 | int changed = 0; |
545 | 546 | ||
546 | spin_lock_irq(&mts->lock); | 547 | spin_lock_irq(&mts->lock); |
547 | if (mts->time[idx] != uctl->value.integer.value[0]) { | 548 | if (mts->time[idx] != time) { |
548 | changed = 1; | 549 | changed = 1; |
549 | mts->time[idx] = uctl->value.integer.value[0]; | 550 | mts->time[idx] = time; |
550 | } | 551 | } |
551 | spin_unlock_irq(&mts->lock); | 552 | spin_unlock_irq(&mts->lock); |
552 | 553 | ||
@@ -636,6 +637,8 @@ static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl, | |||
636 | struct mts64 *mts = snd_kcontrol_chip(kctl); | 637 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
637 | int changed = 0; | 638 | int changed = 0; |
638 | 639 | ||
640 | if (uctl->value.enumerated.item[0] >= 5) | ||
641 | return -EINVAL; | ||
639 | spin_lock_irq(&mts->lock); | 642 | spin_lock_irq(&mts->lock); |
640 | if (mts->fps != uctl->value.enumerated.item[0]) { | 643 | if (mts->fps != uctl->value.enumerated.item[0]) { |
641 | changed = 1; | 644 | changed = 1; |
@@ -662,7 +665,7 @@ static int __devinit snd_mts64_ctl_create(struct snd_card *card, | |||
662 | struct mts64 *mts) | 665 | struct mts64 *mts) |
663 | { | 666 | { |
664 | int err, i; | 667 | int err, i; |
665 | static struct snd_kcontrol_new *control[] = { | 668 | static struct snd_kcontrol_new *control[] __devinitdata = { |
666 | &mts64_ctl_smpte_switch, | 669 | &mts64_ctl_smpte_switch, |
667 | &mts64_ctl_smpte_time_hours, | 670 | &mts64_ctl_smpte_time_hours, |
668 | &mts64_ctl_smpte_time_minutes, | 671 | &mts64_ctl_smpte_time_minutes, |
@@ -1004,6 +1007,8 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev) | |||
1004 | 1007 | ||
1005 | platform_set_drvdata(pdev, card); | 1008 | platform_set_drvdata(pdev, card); |
1006 | 1009 | ||
1010 | snd_card_set_dev(card, &pdev->dev); | ||
1011 | |||
1007 | /* At this point card will be usable */ | 1012 | /* At this point card will be usable */ |
1008 | if ((err = snd_card_register(card)) < 0) { | 1013 | if ((err = snd_card_register(card)) < 0) { |
1009 | snd_printd("Cannot register card\n"); | 1014 | snd_printd("Cannot register card\n"); |
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index a2b9ce060295..ebe4359047cb 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c | |||
@@ -327,6 +327,7 @@ static int snd_opl3_free(struct snd_opl3 *opl3) | |||
327 | snd_assert(opl3 != NULL, return -ENXIO); | 327 | snd_assert(opl3 != NULL, return -ENXIO); |
328 | if (opl3->private_free) | 328 | if (opl3->private_free) |
329 | opl3->private_free(opl3); | 329 | opl3->private_free(opl3); |
330 | snd_opl3_clear_patches(opl3); | ||
330 | release_and_free_resource(opl3->res_l_port); | 331 | release_and_free_resource(opl3->res_l_port); |
331 | release_and_free_resource(opl3->res_r_port); | 332 | release_and_free_resource(opl3->res_r_port); |
332 | kfree(opl3); | 333 | kfree(opl3); |
@@ -360,7 +361,6 @@ int snd_opl3_new(struct snd_card *card, | |||
360 | opl3->hardware = hardware; | 361 | opl3->hardware = hardware; |
361 | spin_lock_init(&opl3->reg_lock); | 362 | spin_lock_init(&opl3->reg_lock); |
362 | spin_lock_init(&opl3->timer_lock); | 363 | spin_lock_init(&opl3->timer_lock); |
363 | mutex_init(&opl3->access_mutex); | ||
364 | 364 | ||
365 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) { | 365 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) { |
366 | snd_opl3_free(opl3); | 366 | snd_opl3_free(opl3); |
@@ -496,6 +496,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, | |||
496 | return err; | 496 | return err; |
497 | } | 497 | } |
498 | hw->private_data = opl3; | 498 | hw->private_data = opl3; |
499 | hw->exclusive = 1; | ||
499 | #ifdef CONFIG_SND_OSSEMUL | 500 | #ifdef CONFIG_SND_OSSEMUL |
500 | if (device == 0) { | 501 | if (device == 0) { |
501 | hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM; | 502 | hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM; |
@@ -521,8 +522,10 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, | |||
521 | /* operators - only ioctl */ | 522 | /* operators - only ioctl */ |
522 | hw->ops.open = snd_opl3_open; | 523 | hw->ops.open = snd_opl3_open; |
523 | hw->ops.ioctl = snd_opl3_ioctl; | 524 | hw->ops.ioctl = snd_opl3_ioctl; |
525 | hw->ops.write = snd_opl3_write; | ||
524 | hw->ops.release = snd_opl3_release; | 526 | hw->ops.release = snd_opl3_release; |
525 | 527 | ||
528 | opl3->hwdep = hw; | ||
526 | opl3->seq_dev_num = seq_device; | 529 | opl3->seq_dev_num = seq_device; |
527 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | 530 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) |
528 | if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3, | 531 | if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3, |
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index 3557b6e20eb5..cebcb8b78acb 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c | |||
@@ -289,8 +289,6 @@ static int snd_opl3_oss_map[MAX_OPL3_VOICES] = { | |||
289 | void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | 289 | void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) |
290 | { | 290 | { |
291 | struct snd_opl3 *opl3; | 291 | struct snd_opl3 *opl3; |
292 | struct snd_seq_instr wanted; | ||
293 | struct snd_seq_kinstr *kinstr; | ||
294 | int instr_4op; | 292 | int instr_4op; |
295 | 293 | ||
296 | int voice; | 294 | int voice; |
@@ -306,11 +304,13 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
306 | unsigned char voice_offset; | 304 | unsigned char voice_offset; |
307 | unsigned short opl3_reg; | 305 | unsigned short opl3_reg; |
308 | unsigned char reg_val; | 306 | unsigned char reg_val; |
307 | unsigned char prg, bank; | ||
309 | 308 | ||
310 | int key = note; | 309 | int key = note; |
311 | unsigned char fnum, blocknum; | 310 | unsigned char fnum, blocknum; |
312 | int i; | 311 | int i; |
313 | 312 | ||
313 | struct fm_patch *patch; | ||
314 | struct fm_instrument *fm; | 314 | struct fm_instrument *fm; |
315 | unsigned long flags; | 315 | unsigned long flags; |
316 | 316 | ||
@@ -320,19 +320,17 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
320 | snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n", | 320 | snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n", |
321 | chan->number, chan->midi_program, note, vel); | 321 | chan->number, chan->midi_program, note, vel); |
322 | #endif | 322 | #endif |
323 | wanted.cluster = 0; | ||
324 | wanted.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3; | ||
325 | 323 | ||
326 | /* in SYNTH mode, application takes care of voices */ | 324 | /* in SYNTH mode, application takes care of voices */ |
327 | /* in SEQ mode, drum voice numbers are notes on drum channel */ | 325 | /* in SEQ mode, drum voice numbers are notes on drum channel */ |
328 | if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { | 326 | if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { |
329 | if (chan->drum_channel) { | 327 | if (chan->drum_channel) { |
330 | /* percussion instruments are located in bank 128 */ | 328 | /* percussion instruments are located in bank 128 */ |
331 | wanted.bank = 128; | 329 | bank = 128; |
332 | wanted.prg = note; | 330 | prg = note; |
333 | } else { | 331 | } else { |
334 | wanted.bank = chan->gm_bank_select; | 332 | bank = chan->gm_bank_select; |
335 | wanted.prg = chan->midi_program; | 333 | prg = chan->midi_program; |
336 | } | 334 | } |
337 | } else { | 335 | } else { |
338 | /* Prepare for OSS mode */ | 336 | /* Prepare for OSS mode */ |
@@ -340,8 +338,8 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
340 | return; | 338 | return; |
341 | 339 | ||
342 | /* OSS instruments are located in bank 127 */ | 340 | /* OSS instruments are located in bank 127 */ |
343 | wanted.bank = 127; | 341 | bank = 127; |
344 | wanted.prg = chan->midi_program; | 342 | prg = chan->midi_program; |
345 | } | 343 | } |
346 | 344 | ||
347 | spin_lock_irqsave(&opl3->voice_lock, flags); | 345 | spin_lock_irqsave(&opl3->voice_lock, flags); |
@@ -353,15 +351,14 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
353 | } | 351 | } |
354 | 352 | ||
355 | __extra_prg: | 353 | __extra_prg: |
356 | kinstr = snd_seq_instr_find(opl3->ilist, &wanted, 1, 0); | 354 | patch = snd_opl3_find_patch(opl3, prg, bank, 0); |
357 | if (kinstr == NULL) { | 355 | if (!patch) { |
358 | spin_unlock_irqrestore(&opl3->voice_lock, flags); | 356 | spin_unlock_irqrestore(&opl3->voice_lock, flags); |
359 | return; | 357 | return; |
360 | } | 358 | } |
361 | 359 | ||
362 | fm = KINSTR_DATA(kinstr); | 360 | fm = &patch->inst; |
363 | 361 | switch (patch->type) { | |
364 | switch (fm->type) { | ||
365 | case FM_PATCH_OPL2: | 362 | case FM_PATCH_OPL2: |
366 | instr_4op = 0; | 363 | instr_4op = 0; |
367 | break; | 364 | break; |
@@ -371,14 +368,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
371 | break; | 368 | break; |
372 | } | 369 | } |
373 | default: | 370 | default: |
374 | snd_seq_instr_free_use(opl3->ilist, kinstr); | ||
375 | spin_unlock_irqrestore(&opl3->voice_lock, flags); | 371 | spin_unlock_irqrestore(&opl3->voice_lock, flags); |
376 | return; | 372 | return; |
377 | } | 373 | } |
378 | |||
379 | #ifdef DEBUG_MIDI | 374 | #ifdef DEBUG_MIDI |
380 | snd_printk(" --> OPL%i instrument: %s\n", | 375 | snd_printk(" --> OPL%i instrument: %s\n", |
381 | instr_4op ? 3 : 2, kinstr->name); | 376 | instr_4op ? 3 : 2, patch->name); |
382 | #endif | 377 | #endif |
383 | /* in SYNTH mode, application takes care of voices */ | 378 | /* in SYNTH mode, application takes care of voices */ |
384 | /* in SEQ mode, allocate voice on free OPL3 channel */ | 379 | /* in SEQ mode, allocate voice on free OPL3 channel */ |
@@ -569,8 +564,6 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
569 | /* get extra pgm, but avoid possible loops */ | 564 | /* get extra pgm, but avoid possible loops */ |
570 | extra_prg = (extra_prg) ? 0 : fm->modes; | 565 | extra_prg = (extra_prg) ? 0 : fm->modes; |
571 | 566 | ||
572 | snd_seq_instr_free_use(opl3->ilist, kinstr); | ||
573 | |||
574 | /* do the bookkeeping */ | 567 | /* do the bookkeeping */ |
575 | vp->time = opl3->use_time++; | 568 | vp->time = opl3->use_time++; |
576 | vp->note = key; | 569 | vp->note = key; |
@@ -601,12 +594,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
601 | /* allocate extra program if specified in patch library */ | 594 | /* allocate extra program if specified in patch library */ |
602 | if (extra_prg) { | 595 | if (extra_prg) { |
603 | if (extra_prg > 128) { | 596 | if (extra_prg > 128) { |
604 | wanted.bank = 128; | 597 | bank = 128; |
605 | /* percussions start at 35 */ | 598 | /* percussions start at 35 */ |
606 | wanted.prg = extra_prg - 128 + 35 - 1; | 599 | prg = extra_prg - 128 + 35 - 1; |
607 | } else { | 600 | } else { |
608 | wanted.bank = 0; | 601 | bank = 0; |
609 | wanted.prg = extra_prg - 1; | 602 | prg = extra_prg - 1; |
610 | } | 603 | } |
611 | #ifdef DEBUG_MIDI | 604 | #ifdef DEBUG_MIDI |
612 | snd_printk(" *** allocating extra program\n"); | 605 | snd_printk(" *** allocating extra program\n"); |
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index 5fd3a4c95626..239347f26154 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c | |||
@@ -195,17 +195,6 @@ static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg) | |||
195 | 195 | ||
196 | /* load patch */ | 196 | /* load patch */ |
197 | 197 | ||
198 | /* offsets for SBI params */ | ||
199 | #define AM_VIB 0 | ||
200 | #define KSL_LEVEL 2 | ||
201 | #define ATTACK_DECAY 4 | ||
202 | #define SUSTAIN_RELEASE 6 | ||
203 | #define WAVE_SELECT 8 | ||
204 | |||
205 | /* offset for SBI instrument */ | ||
206 | #define CONNECTION 10 | ||
207 | #define OFFSET_4OP 11 | ||
208 | |||
209 | /* from sound_config.h */ | 198 | /* from sound_config.h */ |
210 | #define SBFM_MAXINSTR 256 | 199 | #define SBFM_MAXINSTR 256 |
211 | 200 | ||
@@ -213,112 +202,42 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, | |||
213 | const char __user *buf, int offs, int count) | 202 | const char __user *buf, int offs, int count) |
214 | { | 203 | { |
215 | struct snd_opl3 *opl3; | 204 | struct snd_opl3 *opl3; |
216 | int err = -EINVAL; | 205 | struct sbi_instrument sbi; |
206 | char name[32]; | ||
207 | int err, type; | ||
217 | 208 | ||
218 | snd_assert(arg != NULL, return -ENXIO); | 209 | snd_assert(arg != NULL, return -ENXIO); |
219 | opl3 = arg->private_data; | 210 | opl3 = arg->private_data; |
220 | 211 | ||
221 | if ((format == FM_PATCH) || (format == OPL3_PATCH)) { | 212 | if (format == FM_PATCH) |
222 | struct sbi_instrument sbi; | 213 | type = FM_PATCH_OPL2; |
214 | else if (format == OPL3_PATCH) | ||
215 | type = FM_PATCH_OPL3; | ||
216 | else | ||
217 | return -EINVAL; | ||
223 | 218 | ||
224 | size_t size; | 219 | if (count < (int)sizeof(sbi)) { |
225 | struct snd_seq_instr_header *put; | 220 | snd_printk("FM Error: Patch record too short\n"); |
226 | struct snd_seq_instr_data *data; | 221 | return -EINVAL; |
227 | struct fm_xinstrument *xinstr; | 222 | } |
223 | if (copy_from_user(&sbi, buf, sizeof(sbi))) | ||
224 | return -EFAULT; | ||
228 | 225 | ||
229 | struct snd_seq_event ev; | 226 | if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) { |
230 | int i; | 227 | snd_printk("FM Error: Invalid instrument number %d\n", |
228 | sbi.channel); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | 231 | ||
232 | mm_segment_t fs; | 232 | memset(name, 0, sizeof(name)); |
233 | sprintf(name, "Chan%d", sbi.channel); | ||
233 | 234 | ||
234 | if (count < (int)sizeof(sbi)) { | 235 | err = snd_opl3_load_patch(opl3, sbi.channel, 127, type, name, NULL, |
235 | snd_printk("FM Error: Patch record too short\n"); | 236 | sbi.operators); |
236 | return -EINVAL; | 237 | if (err < 0) |
237 | } | 238 | return err; |
238 | if (copy_from_user(&sbi, buf, sizeof(sbi))) | ||
239 | return -EFAULT; | ||
240 | 239 | ||
241 | if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) { | 240 | return sizeof(sbi); |
242 | snd_printk("FM Error: Invalid instrument number %d\n", sbi.channel); | ||
243 | return -EINVAL; | ||
244 | } | ||
245 | |||
246 | size = sizeof(*put) + sizeof(struct fm_xinstrument); | ||
247 | put = kzalloc(size, GFP_KERNEL); | ||
248 | if (put == NULL) | ||
249 | return -ENOMEM; | ||
250 | /* build header */ | ||
251 | data = &put->data; | ||
252 | data->type = SNDRV_SEQ_INSTR_ATYPE_DATA; | ||
253 | strcpy(data->data.format, SNDRV_SEQ_INSTR_ID_OPL2_3); | ||
254 | /* build data section */ | ||
255 | xinstr = (struct fm_xinstrument *)(data + 1); | ||
256 | xinstr->stype = FM_STRU_INSTR; | ||
257 | |||
258 | for (i = 0; i < 2; i++) { | ||
259 | xinstr->op[i].am_vib = sbi.operators[AM_VIB + i]; | ||
260 | xinstr->op[i].ksl_level = sbi.operators[KSL_LEVEL + i]; | ||
261 | xinstr->op[i].attack_decay = sbi.operators[ATTACK_DECAY + i]; | ||
262 | xinstr->op[i].sustain_release = sbi.operators[SUSTAIN_RELEASE + i]; | ||
263 | xinstr->op[i].wave_select = sbi.operators[WAVE_SELECT + i]; | ||
264 | } | ||
265 | xinstr->feedback_connection[0] = sbi.operators[CONNECTION]; | ||
266 | |||
267 | if (format == OPL3_PATCH) { | ||
268 | xinstr->type = FM_PATCH_OPL3; | ||
269 | for (i = 0; i < 2; i++) { | ||
270 | xinstr->op[i+2].am_vib = sbi.operators[OFFSET_4OP + AM_VIB + i]; | ||
271 | xinstr->op[i+2].ksl_level = sbi.operators[OFFSET_4OP + KSL_LEVEL + i]; | ||
272 | xinstr->op[i+2].attack_decay = sbi.operators[OFFSET_4OP + ATTACK_DECAY + i]; | ||
273 | xinstr->op[i+2].sustain_release = sbi.operators[OFFSET_4OP + SUSTAIN_RELEASE + i]; | ||
274 | xinstr->op[i+2].wave_select = sbi.operators[OFFSET_4OP + WAVE_SELECT + i]; | ||
275 | } | ||
276 | xinstr->feedback_connection[1] = sbi.operators[OFFSET_4OP + CONNECTION]; | ||
277 | } else { | ||
278 | xinstr->type = FM_PATCH_OPL2; | ||
279 | } | ||
280 | |||
281 | put->id.instr.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3; | ||
282 | put->id.instr.bank = 127; | ||
283 | put->id.instr.prg = sbi.channel; | ||
284 | put->cmd = SNDRV_SEQ_INSTR_PUT_CMD_CREATE; | ||
285 | |||
286 | memset (&ev, 0, sizeof(ev)); | ||
287 | ev.source.client = SNDRV_SEQ_CLIENT_OSS; | ||
288 | ev.dest = arg->addr; | ||
289 | |||
290 | ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARUSR; | ||
291 | ev.queue = SNDRV_SEQ_QUEUE_DIRECT; | ||
292 | |||
293 | fs = snd_enter_user(); | ||
294 | __again: | ||
295 | ev.type = SNDRV_SEQ_EVENT_INSTR_PUT; | ||
296 | ev.data.ext.len = size; | ||
297 | ev.data.ext.ptr = put; | ||
298 | |||
299 | err = snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev, | ||
300 | opl3->seq_client, 0, 0); | ||
301 | if (err == -EBUSY) { | ||
302 | struct snd_seq_instr_header remove; | ||
303 | |||
304 | memset (&remove, 0, sizeof(remove)); | ||
305 | remove.cmd = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE; | ||
306 | remove.id.instr = put->id.instr; | ||
307 | |||
308 | /* remove instrument */ | ||
309 | ev.type = SNDRV_SEQ_EVENT_INSTR_FREE; | ||
310 | ev.data.ext.len = sizeof(remove); | ||
311 | ev.data.ext.ptr = &remove; | ||
312 | |||
313 | snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev, | ||
314 | opl3->seq_client, 0, 0); | ||
315 | goto __again; | ||
316 | } | ||
317 | snd_leave_user(fs); | ||
318 | |||
319 | kfree(put); | ||
320 | } | ||
321 | return err; | ||
322 | } | 241 | } |
323 | 242 | ||
324 | /* ioctl */ | 243 | /* ioctl */ |
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index 96762c9d4855..2d33f53d36b8 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c | |||
@@ -51,14 +51,15 @@ void snd_opl3_synth_use_dec(struct snd_opl3 * opl3) | |||
51 | int snd_opl3_synth_setup(struct snd_opl3 * opl3) | 51 | int snd_opl3_synth_setup(struct snd_opl3 * opl3) |
52 | { | 52 | { |
53 | int idx; | 53 | int idx; |
54 | struct snd_hwdep *hwdep = opl3->hwdep; | ||
54 | 55 | ||
55 | mutex_lock(&opl3->access_mutex); | 56 | mutex_lock(&hwdep->open_mutex); |
56 | if (opl3->used) { | 57 | if (hwdep->used) { |
57 | mutex_unlock(&opl3->access_mutex); | 58 | mutex_unlock(&hwdep->open_mutex); |
58 | return -EBUSY; | 59 | return -EBUSY; |
59 | } | 60 | } |
60 | opl3->used++; | 61 | hwdep->used++; |
61 | mutex_unlock(&opl3->access_mutex); | 62 | mutex_unlock(&hwdep->open_mutex); |
62 | 63 | ||
63 | snd_opl3_reset(opl3); | 64 | snd_opl3_reset(opl3); |
64 | 65 | ||
@@ -81,6 +82,7 @@ int snd_opl3_synth_setup(struct snd_opl3 * opl3) | |||
81 | void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) | 82 | void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) |
82 | { | 83 | { |
83 | unsigned long flags; | 84 | unsigned long flags; |
85 | struct snd_hwdep *hwdep; | ||
84 | 86 | ||
85 | /* Stop system timer */ | 87 | /* Stop system timer */ |
86 | spin_lock_irqsave(&opl3->sys_timer_lock, flags); | 88 | spin_lock_irqsave(&opl3->sys_timer_lock, flags); |
@@ -91,9 +93,11 @@ void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) | |||
91 | spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); | 93 | spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); |
92 | 94 | ||
93 | snd_opl3_reset(opl3); | 95 | snd_opl3_reset(opl3); |
94 | mutex_lock(&opl3->access_mutex); | 96 | hwdep = opl3->hwdep; |
95 | opl3->used--; | 97 | mutex_lock(&hwdep->open_mutex); |
96 | mutex_unlock(&opl3->access_mutex); | 98 | hwdep->used--; |
99 | mutex_unlock(&hwdep->open_mutex); | ||
100 | wake_up(&hwdep->open_wait); | ||
97 | } | 101 | } |
98 | 102 | ||
99 | static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe * info) | 103 | static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe * info) |
@@ -152,15 +156,7 @@ static int snd_opl3_synth_event_input(struct snd_seq_event * ev, int direct, | |||
152 | { | 156 | { |
153 | struct snd_opl3 *opl3 = private_data; | 157 | struct snd_opl3 *opl3 = private_data; |
154 | 158 | ||
155 | if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN && | 159 | snd_midi_process_event(&opl3_ops, ev, opl3->chset); |
156 | ev->type <= SNDRV_SEQ_EVENT_INSTR_CHANGE) { | ||
157 | if (direct) { | ||
158 | snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, ev, | ||
159 | opl3->seq_client, atomic, hop); | ||
160 | } | ||
161 | } else { | ||
162 | snd_midi_process_event(&opl3_ops, ev, opl3->chset); | ||
163 | } | ||
164 | return 0; | 160 | return 0; |
165 | } | 161 | } |
166 | 162 | ||
@@ -249,16 +245,6 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev) | |||
249 | return err; | 245 | return err; |
250 | } | 246 | } |
251 | 247 | ||
252 | /* initialize instrument list */ | ||
253 | opl3->ilist = snd_seq_instr_list_new(); | ||
254 | if (opl3->ilist == NULL) { | ||
255 | snd_seq_delete_kernel_client(client); | ||
256 | opl3->seq_client = -1; | ||
257 | return -ENOMEM; | ||
258 | } | ||
259 | opl3->ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT; | ||
260 | snd_seq_fm_init(&opl3->fm_ops, NULL); | ||
261 | |||
262 | /* setup system timer */ | 248 | /* setup system timer */ |
263 | init_timer(&opl3->tlist); | 249 | init_timer(&opl3->tlist); |
264 | opl3->tlist.function = snd_opl3_timer_func; | 250 | opl3->tlist.function = snd_opl3_timer_func; |
@@ -287,8 +273,6 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev) | |||
287 | snd_seq_delete_kernel_client(opl3->seq_client); | 273 | snd_seq_delete_kernel_client(opl3->seq_client); |
288 | opl3->seq_client = -1; | 274 | opl3->seq_client = -1; |
289 | } | 275 | } |
290 | if (opl3->ilist) | ||
291 | snd_seq_instr_list_free(&opl3->ilist); | ||
292 | return 0; | 276 | return 0; |
293 | } | 277 | } |
294 | 278 | ||
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c index a4b3543a7118..a7bf7a4b1f85 100644 --- a/sound/drivers/opl3/opl3_synth.c +++ b/sound/drivers/opl3/opl3_synth.c | |||
@@ -76,16 +76,6 @@ static int snd_opl3_set_connection(struct snd_opl3 * opl3, int connection); | |||
76 | */ | 76 | */ |
77 | int snd_opl3_open(struct snd_hwdep * hw, struct file *file) | 77 | int snd_opl3_open(struct snd_hwdep * hw, struct file *file) |
78 | { | 78 | { |
79 | struct snd_opl3 *opl3 = hw->private_data; | ||
80 | |||
81 | mutex_lock(&opl3->access_mutex); | ||
82 | if (opl3->used) { | ||
83 | mutex_unlock(&opl3->access_mutex); | ||
84 | return -EAGAIN; | ||
85 | } | ||
86 | opl3->used++; | ||
87 | mutex_unlock(&opl3->access_mutex); | ||
88 | |||
89 | return 0; | 79 | return 0; |
90 | } | 80 | } |
91 | 81 | ||
@@ -165,6 +155,10 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file, | |||
165 | #endif | 155 | #endif |
166 | return snd_opl3_set_connection(opl3, (int) arg); | 156 | return snd_opl3_set_connection(opl3, (int) arg); |
167 | 157 | ||
158 | case SNDRV_DM_FM_IOCTL_CLEAR_PATCHES: | ||
159 | snd_opl3_clear_patches(opl3); | ||
160 | return 0; | ||
161 | |||
168 | #ifdef CONFIG_SND_DEBUG | 162 | #ifdef CONFIG_SND_DEBUG |
169 | default: | 163 | default: |
170 | snd_printk("unknown IOCTL: 0x%x\n", cmd); | 164 | snd_printk("unknown IOCTL: 0x%x\n", cmd); |
@@ -181,12 +175,172 @@ int snd_opl3_release(struct snd_hwdep * hw, struct file *file) | |||
181 | struct snd_opl3 *opl3 = hw->private_data; | 175 | struct snd_opl3 *opl3 = hw->private_data; |
182 | 176 | ||
183 | snd_opl3_reset(opl3); | 177 | snd_opl3_reset(opl3); |
184 | mutex_lock(&opl3->access_mutex); | 178 | return 0; |
185 | opl3->used--; | 179 | } |
186 | mutex_unlock(&opl3->access_mutex); | 180 | |
181 | /* | ||
182 | * write the device - load patches | ||
183 | */ | ||
184 | long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count, | ||
185 | loff_t *offset) | ||
186 | { | ||
187 | struct snd_opl3 *opl3 = hw->private_data; | ||
188 | long result = 0; | ||
189 | int err = 0; | ||
190 | struct sbi_patch inst; | ||
191 | |||
192 | while (count >= sizeof(inst)) { | ||
193 | unsigned char type; | ||
194 | if (copy_from_user(&inst, buf, sizeof(inst))) | ||
195 | return -EFAULT; | ||
196 | if (!memcmp(inst.key, FM_KEY_SBI, 4) || | ||
197 | !memcmp(inst.key, FM_KEY_2OP, 4)) | ||
198 | type = FM_PATCH_OPL2; | ||
199 | else if (!memcmp(inst.key, FM_KEY_4OP, 4)) | ||
200 | type = FM_PATCH_OPL3; | ||
201 | else /* invalid type */ | ||
202 | break; | ||
203 | err = snd_opl3_load_patch(opl3, inst.prog, inst.bank, type, | ||
204 | inst.name, inst.extension, | ||
205 | inst.data); | ||
206 | if (err < 0) | ||
207 | break; | ||
208 | result += sizeof(inst); | ||
209 | count -= sizeof(inst); | ||
210 | } | ||
211 | return result > 0 ? result : err; | ||
212 | } | ||
213 | |||
214 | |||
215 | /* | ||
216 | * Patch management | ||
217 | */ | ||
218 | |||
219 | /* offsets for SBI params */ | ||
220 | #define AM_VIB 0 | ||
221 | #define KSL_LEVEL 2 | ||
222 | #define ATTACK_DECAY 4 | ||
223 | #define SUSTAIN_RELEASE 6 | ||
224 | #define WAVE_SELECT 8 | ||
225 | |||
226 | /* offset for SBI instrument */ | ||
227 | #define CONNECTION 10 | ||
228 | #define OFFSET_4OP 11 | ||
229 | |||
230 | /* | ||
231 | * load a patch, obviously. | ||
232 | * | ||
233 | * loaded on the given program and bank numbers with the given type | ||
234 | * (FM_PATCH_OPLx). | ||
235 | * data is the pointer of SBI record _without_ header (key and name). | ||
236 | * name is the name string of the patch. | ||
237 | * ext is the extension data of 7 bytes long (stored in name of SBI | ||
238 | * data up to offset 25), or NULL to skip. | ||
239 | * return 0 if successful or a negative error code. | ||
240 | */ | ||
241 | int snd_opl3_load_patch(struct snd_opl3 *opl3, | ||
242 | int prog, int bank, int type, | ||
243 | const char *name, | ||
244 | const unsigned char *ext, | ||
245 | const unsigned char *data) | ||
246 | { | ||
247 | struct fm_patch *patch; | ||
248 | int i; | ||
249 | |||
250 | patch = snd_opl3_find_patch(opl3, prog, bank, 1); | ||
251 | if (!patch) | ||
252 | return -ENOMEM; | ||
253 | |||
254 | patch->type = type; | ||
255 | |||
256 | for (i = 0; i < 2; i++) { | ||
257 | patch->inst.op[i].am_vib = data[AM_VIB + i]; | ||
258 | patch->inst.op[i].ksl_level = data[KSL_LEVEL + i]; | ||
259 | patch->inst.op[i].attack_decay = data[ATTACK_DECAY + i]; | ||
260 | patch->inst.op[i].sustain_release = data[SUSTAIN_RELEASE + i]; | ||
261 | patch->inst.op[i].wave_select = data[WAVE_SELECT + i]; | ||
262 | } | ||
263 | patch->inst.feedback_connection[0] = data[CONNECTION]; | ||
264 | |||
265 | if (type == FM_PATCH_OPL3) { | ||
266 | for (i = 0; i < 2; i++) { | ||
267 | patch->inst.op[i+2].am_vib = | ||
268 | data[OFFSET_4OP + AM_VIB + i]; | ||
269 | patch->inst.op[i+2].ksl_level = | ||
270 | data[OFFSET_4OP + KSL_LEVEL + i]; | ||
271 | patch->inst.op[i+2].attack_decay = | ||
272 | data[OFFSET_4OP + ATTACK_DECAY + i]; | ||
273 | patch->inst.op[i+2].sustain_release = | ||
274 | data[OFFSET_4OP + SUSTAIN_RELEASE + i]; | ||
275 | patch->inst.op[i+2].wave_select = | ||
276 | data[OFFSET_4OP + WAVE_SELECT + i]; | ||
277 | } | ||
278 | patch->inst.feedback_connection[1] = | ||
279 | data[OFFSET_4OP + CONNECTION]; | ||
280 | } | ||
281 | |||
282 | if (ext) { | ||
283 | patch->inst.echo_delay = ext[0]; | ||
284 | patch->inst.echo_atten = ext[1]; | ||
285 | patch->inst.chorus_spread = ext[2]; | ||
286 | patch->inst.trnsps = ext[3]; | ||
287 | patch->inst.fix_dur = ext[4]; | ||
288 | patch->inst.modes = ext[5]; | ||
289 | patch->inst.fix_key = ext[6]; | ||
290 | } | ||
291 | |||
292 | if (name) | ||
293 | strlcpy(patch->name, name, sizeof(patch->name)); | ||
187 | 294 | ||
188 | return 0; | 295 | return 0; |
189 | } | 296 | } |
297 | EXPORT_SYMBOL(snd_opl3_load_patch); | ||
298 | |||
299 | /* | ||
300 | * find a patch with the given program and bank numbers, returns its pointer | ||
301 | * if no matching patch is found and create_patch is set, it creates a | ||
302 | * new patch object. | ||
303 | */ | ||
304 | struct fm_patch *snd_opl3_find_patch(struct snd_opl3 *opl3, int prog, int bank, | ||
305 | int create_patch) | ||
306 | { | ||
307 | /* pretty dumb hash key */ | ||
308 | unsigned int key = (prog + bank) % OPL3_PATCH_HASH_SIZE; | ||
309 | struct fm_patch *patch; | ||
310 | |||
311 | for (patch = opl3->patch_table[key]; patch; patch = patch->next) { | ||
312 | if (patch->prog == prog && patch->bank == bank) | ||
313 | return patch; | ||
314 | } | ||
315 | if (!create_patch) | ||
316 | return NULL; | ||
317 | |||
318 | patch = kzalloc(sizeof(*patch), GFP_KERNEL); | ||
319 | if (!patch) | ||
320 | return NULL; | ||
321 | patch->prog = prog; | ||
322 | patch->bank = bank; | ||
323 | patch->next = opl3->patch_table[key]; | ||
324 | opl3->patch_table[key] = patch; | ||
325 | return patch; | ||
326 | } | ||
327 | EXPORT_SYMBOL(snd_opl3_find_patch); | ||
328 | |||
329 | /* | ||
330 | * Clear all patches of the given OPL3 instance | ||
331 | */ | ||
332 | void snd_opl3_clear_patches(struct snd_opl3 *opl3) | ||
333 | { | ||
334 | int i; | ||
335 | for (i = 0; i < OPL3_PATCH_HASH_SIZE; i++) { | ||
336 | struct fm_patch *patch, *next; | ||
337 | for (patch = opl3->patch_table[i]; patch; patch = next) { | ||
338 | next = patch->next; | ||
339 | kfree(patch); | ||
340 | } | ||
341 | } | ||
342 | memset(opl3->patch_table, 0, sizeof(opl3->patch_table)); | ||
343 | } | ||
190 | 344 | ||
191 | /* ------------------------------ */ | 345 | /* ------------------------------ */ |
192 | 346 | ||
diff --git a/sound/drivers/pcm-indirect2.c b/sound/drivers/pcm-indirect2.c new file mode 100644 index 000000000000..3c93c23e4883 --- /dev/null +++ b/sound/drivers/pcm-indirect2.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * Helper functions for indirect PCM data transfer to a simple FIFO in | ||
3 | * hardware (small, no possibility to read "hardware io position", | ||
4 | * updating position done by interrupt, ...) | ||
5 | * | ||
6 | * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> | ||
7 | * | ||
8 | * Based on "pcm-indirect.h" (alsa-driver-1.0.13) by | ||
9 | * | ||
10 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
11 | * Jaroslav Kysela <perex@suse.cz> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | /* snd_printk/d() */ | ||
29 | #include <sound/core.h> | ||
30 | /* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t | ||
31 | * snd_pcm_period_elapsed() */ | ||
32 | #include <sound/pcm.h> | ||
33 | |||
34 | #include "pcm-indirect2.h" | ||
35 | |||
36 | #ifdef SND_PCM_INDIRECT2_STAT | ||
37 | /* jiffies */ | ||
38 | #include <linux/jiffies.h> | ||
39 | |||
40 | void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream, | ||
41 | struct snd_pcm_indirect2 *rec) | ||
42 | { | ||
43 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
44 | int i; | ||
45 | int j; | ||
46 | int k; | ||
47 | int seconds = (rec->lastbytetime - rec->firstbytetime) / HZ; | ||
48 | |||
49 | snd_printk(KERN_DEBUG "STAT: mul_elapsed: %u, mul_elapsed_real: %d, " | ||
50 | "irq_occured: %d\n", | ||
51 | rec->mul_elapsed, rec->mul_elapsed_real, rec->irq_occured); | ||
52 | snd_printk(KERN_DEBUG "STAT: min_multiple: %d (irqs/period)\n", | ||
53 | rec->min_multiple); | ||
54 | snd_printk(KERN_DEBUG "STAT: firstbytetime: %lu, lastbytetime: %lu, " | ||
55 | "firstzerotime: %lu\n", | ||
56 | rec->firstbytetime, rec->lastbytetime, rec->firstzerotime); | ||
57 | snd_printk(KERN_DEBUG "STAT: bytes2hw: %u Bytes => (by runtime->rate) " | ||
58 | "length: %d s\n", | ||
59 | rec->bytes2hw, rec->bytes2hw / 2 / 2 / runtime->rate); | ||
60 | snd_printk(KERN_DEBUG "STAT: (by measurement) length: %d => " | ||
61 | "rate: %d Bytes/s = %d Frames/s|Hz\n", | ||
62 | seconds, rec->bytes2hw / seconds, | ||
63 | rec->bytes2hw / 2 / 2 / seconds); | ||
64 | snd_printk(KERN_DEBUG | ||
65 | "STAT: zeros2hw: %u = %d ms ~ %d * %d zero copies\n", | ||
66 | rec->zeros2hw, ((rec->zeros2hw / 2 / 2) * 1000) / | ||
67 | runtime->rate, | ||
68 | rec->zeros2hw / (rec->hw_buffer_size / 2), | ||
69 | (rec->hw_buffer_size / 2)); | ||
70 | snd_printk(KERN_DEBUG "STAT: pointer_calls: %u, lastdifftime: %u\n", | ||
71 | rec->pointer_calls, rec->lastdifftime); | ||
72 | snd_printk(KERN_DEBUG "STAT: sw_io: %d, sw_data: %d\n", rec->sw_io, | ||
73 | rec->sw_data); | ||
74 | snd_printk(KERN_DEBUG "STAT: byte_sizes[]:\n"); | ||
75 | k = 0; | ||
76 | for (j = 0; j < 8; j++) { | ||
77 | for (i = j * 8; i < (j + 1) * 8; i++) | ||
78 | if (rec->byte_sizes[i] != 0) { | ||
79 | snd_printk(KERN_DEBUG "%u: %u", | ||
80 | i, rec->byte_sizes[i]); | ||
81 | k++; | ||
82 | } | ||
83 | if (((k % 8) == 0) && (k != 0)) { | ||
84 | snd_printk(KERN_DEBUG "\n"); | ||
85 | k = 0; | ||
86 | } | ||
87 | } | ||
88 | snd_printk(KERN_DEBUG "\n"); | ||
89 | snd_printk(KERN_DEBUG "STAT: zero_sizes[]:\n"); | ||
90 | for (j = 0; j < 8; j++) { | ||
91 | k = 0; | ||
92 | for (i = j * 8; i < (j + 1) * 8; i++) | ||
93 | if (rec->zero_sizes[i] != 0) | ||
94 | snd_printk(KERN_DEBUG "%u: %u", | ||
95 | i, rec->zero_sizes[i]); | ||
96 | else | ||
97 | k++; | ||
98 | if (!k) | ||
99 | snd_printk(KERN_DEBUG "\n"); | ||
100 | } | ||
101 | snd_printk(KERN_DEBUG "\n"); | ||
102 | snd_printk(KERN_DEBUG "STAT: min_adds[]:\n"); | ||
103 | for (j = 0; j < 8; j++) { | ||
104 | if (rec->min_adds[j] != 0) | ||
105 | snd_printk(KERN_DEBUG "%u: %u", j, rec->min_adds[j]); | ||
106 | } | ||
107 | snd_printk(KERN_DEBUG "\n"); | ||
108 | snd_printk(KERN_DEBUG "STAT: mul_adds[]:\n"); | ||
109 | for (j = 0; j < 8; j++) { | ||
110 | if (rec->mul_adds[j] != 0) | ||
111 | snd_printk(KERN_DEBUG "%u: %u", j, rec->mul_adds[j]); | ||
112 | } | ||
113 | snd_printk(KERN_DEBUG "\n"); | ||
114 | snd_printk(KERN_DEBUG | ||
115 | "STAT: zero_times_saved: %d, zero_times_notsaved: %d\n", | ||
116 | rec->zero_times_saved, rec->zero_times_notsaved); | ||
117 | /* snd_printk(KERN_DEBUG "STAT: zero_times[]\n"); | ||
118 | i = 0; | ||
119 | for (j = 0; j < 3750; j++) { | ||
120 | if (rec->zero_times[j] != 0) { | ||
121 | snd_printk(KERN_DEBUG "%u: %u", j, rec->zero_times[j]); | ||
122 | i++; | ||
123 | } | ||
124 | if (((i % 8) == 0) && (i != 0)) | ||
125 | snd_printk(KERN_DEBUG "\n"); | ||
126 | } | ||
127 | snd_printk(KERN_DEBUG "\n"); */ | ||
128 | return; | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | /* | ||
133 | * _internal_ helper function for playback/capture transfer function | ||
134 | */ | ||
135 | static void | ||
136 | snd_pcm_indirect2_increase_min_periods(struct snd_pcm_substream *substream, | ||
137 | struct snd_pcm_indirect2 *rec, | ||
138 | int isplay, int iscopy, | ||
139 | unsigned int bytes) | ||
140 | { | ||
141 | if (rec->min_periods >= 0) { | ||
142 | if (iscopy) { | ||
143 | rec->sw_io += bytes; | ||
144 | if (rec->sw_io >= rec->sw_buffer_size) | ||
145 | rec->sw_io -= rec->sw_buffer_size; | ||
146 | } else if (isplay) { | ||
147 | /* If application does not write data in multiples of | ||
148 | * a period, move sw_data to the next correctly aligned | ||
149 | * position, so that sw_io can converge to it (in the | ||
150 | * next step). | ||
151 | */ | ||
152 | if (!rec->check_alignment) { | ||
153 | if (rec->bytes2hw % | ||
154 | snd_pcm_lib_period_bytes(substream)) { | ||
155 | unsigned bytes2hw_aligned = | ||
156 | (1 + | ||
157 | (rec->bytes2hw / | ||
158 | snd_pcm_lib_period_bytes | ||
159 | (substream))) * | ||
160 | snd_pcm_lib_period_bytes | ||
161 | (substream); | ||
162 | rec->sw_data = | ||
163 | bytes2hw_aligned % | ||
164 | rec->sw_buffer_size; | ||
165 | #ifdef SND_PCM_INDIRECT2_STAT | ||
166 | snd_printk(KERN_DEBUG | ||
167 | "STAT: @re-align: aligned " | ||
168 | "bytes2hw to next period " | ||
169 | "size boundary: %d " | ||
170 | "(instead of %d)\n", | ||
171 | bytes2hw_aligned, | ||
172 | rec->bytes2hw); | ||
173 | snd_printk(KERN_DEBUG | ||
174 | "STAT: @re-align: sw_data " | ||
175 | "moves to: %d\n", | ||
176 | rec->sw_data); | ||
177 | #endif | ||
178 | } | ||
179 | rec->check_alignment = 1; | ||
180 | } | ||
181 | /* We are at the end and are copying zeros into the | ||
182 | * fifo. | ||
183 | * Now, we have to make sure that sw_io is increased | ||
184 | * until the position of sw_data: Filling the fifo with | ||
185 | * the first zeros means, the last bytes were played. | ||
186 | */ | ||
187 | if (rec->sw_io != rec->sw_data) { | ||
188 | unsigned int diff; | ||
189 | if (rec->sw_data > rec->sw_io) | ||
190 | diff = rec->sw_data - rec->sw_io; | ||
191 | else | ||
192 | diff = (rec->sw_buffer_size - | ||
193 | rec->sw_io) + | ||
194 | rec->sw_data; | ||
195 | if (bytes >= diff) | ||
196 | rec->sw_io = rec->sw_data; | ||
197 | else { | ||
198 | rec->sw_io += bytes; | ||
199 | if (rec->sw_io >= rec->sw_buffer_size) | ||
200 | rec->sw_io -= | ||
201 | rec->sw_buffer_size; | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | rec->min_period_count += bytes; | ||
206 | if (rec->min_period_count >= (rec->hw_buffer_size / 2)) { | ||
207 | rec->min_periods += (rec->min_period_count / | ||
208 | (rec->hw_buffer_size / 2)); | ||
209 | #ifdef SND_PCM_INDIRECT2_STAT | ||
210 | if ((rec->min_period_count / | ||
211 | (rec->hw_buffer_size / 2)) > 7) | ||
212 | snd_printk(KERN_DEBUG | ||
213 | "STAT: more than 7 (%d) min_adds " | ||
214 | "at once - too big to save!\n", | ||
215 | (rec->min_period_count / | ||
216 | (rec->hw_buffer_size / 2))); | ||
217 | else | ||
218 | rec->min_adds[(rec->min_period_count / | ||
219 | (rec->hw_buffer_size / 2))]++; | ||
220 | #endif | ||
221 | rec->min_period_count = (rec->min_period_count % | ||
222 | (rec->hw_buffer_size / 2)); | ||
223 | } | ||
224 | } else if (isplay && iscopy) | ||
225 | rec->min_periods = 0; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * helper function for playback/capture pointer callback | ||
230 | */ | ||
231 | snd_pcm_uframes_t | ||
232 | snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream, | ||
233 | struct snd_pcm_indirect2 *rec) | ||
234 | { | ||
235 | #ifdef SND_PCM_INDIRECT2_STAT | ||
236 | rec->pointer_calls++; | ||
237 | #endif | ||
238 | return bytes_to_frames(substream->runtime, rec->sw_io); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * _internal_ helper function for playback interrupt callback | ||
243 | */ | ||
244 | static void | ||
245 | snd_pcm_indirect2_playback_transfer(struct snd_pcm_substream *substream, | ||
246 | struct snd_pcm_indirect2 *rec, | ||
247 | snd_pcm_indirect2_copy_t copy, | ||
248 | snd_pcm_indirect2_zero_t zero) | ||
249 | { | ||
250 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
251 | snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; | ||
252 | |||
253 | /* runtime->control->appl_ptr: position where ALSA will write next time | ||
254 | * rec->appl_ptr: position where ALSA was last time | ||
255 | * diff: obviously ALSA wrote that much bytes into the intermediate | ||
256 | * buffer since we checked last time | ||
257 | */ | ||
258 | snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr; | ||
259 | |||
260 | if (diff) { | ||
261 | #ifdef SND_PCM_INDIRECT2_STAT | ||
262 | rec->lastdifftime = jiffies; | ||
263 | #endif | ||
264 | if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) | ||
265 | diff += runtime->boundary; | ||
266 | /* number of bytes "added" by ALSA increases the number of | ||
267 | * bytes which are ready to "be transfered to HW"/"played" | ||
268 | * Then, set rec->appl_ptr to not count bytes twice next time. | ||
269 | */ | ||
270 | rec->sw_ready += (int)frames_to_bytes(runtime, diff); | ||
271 | rec->appl_ptr = appl_ptr; | ||
272 | } | ||
273 | if (rec->hw_ready && (rec->sw_ready <= 0)) { | ||
274 | unsigned int bytes; | ||
275 | |||
276 | #ifdef SND_PCM_INDIRECT2_STAT | ||
277 | if (rec->firstzerotime == 0) { | ||
278 | rec->firstzerotime = jiffies; | ||
279 | snd_printk(KERN_DEBUG | ||
280 | "STAT: @firstzerotime: mul_elapsed: %d, " | ||
281 | "min_period_count: %d\n", | ||
282 | rec->mul_elapsed, rec->min_period_count); | ||
283 | snd_printk(KERN_DEBUG | ||
284 | "STAT: @firstzerotime: sw_io: %d, " | ||
285 | "sw_data: %d, appl_ptr: %u\n", | ||
286 | rec->sw_io, rec->sw_data, | ||
287 | (unsigned int)appl_ptr); | ||
288 | } | ||
289 | if ((jiffies - rec->firstzerotime) < 3750) { | ||
290 | rec->zero_times[(jiffies - rec->firstzerotime)]++; | ||
291 | rec->zero_times_saved++; | ||
292 | } else | ||
293 | rec->zero_times_notsaved++; | ||
294 | #endif | ||
295 | bytes = zero(substream, rec); | ||
296 | |||
297 | #ifdef SND_PCM_INDIRECT2_STAT | ||
298 | rec->zeros2hw += bytes; | ||
299 | if (bytes < 64) | ||
300 | rec->zero_sizes[bytes]++; | ||
301 | else | ||
302 | snd_printk(KERN_DEBUG | ||
303 | "STAT: %d zero Bytes copied to hardware at " | ||
304 | "once - too big to save!\n", | ||
305 | bytes); | ||
306 | #endif | ||
307 | snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 0, | ||
308 | bytes); | ||
309 | return; | ||
310 | } | ||
311 | while (rec->hw_ready && (rec->sw_ready > 0)) { | ||
312 | /* sw_to_end: max. number of bytes that can be read/take from | ||
313 | * the current position (sw_data) in _one_ step | ||
314 | */ | ||
315 | unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data; | ||
316 | |||
317 | /* bytes: number of bytes we have available (for reading) */ | ||
318 | unsigned int bytes = rec->sw_ready; | ||
319 | |||
320 | if (sw_to_end < bytes) | ||
321 | bytes = sw_to_end; | ||
322 | if (!bytes) | ||
323 | break; | ||
324 | |||
325 | #ifdef SND_PCM_INDIRECT2_STAT | ||
326 | if (rec->firstbytetime == 0) | ||
327 | rec->firstbytetime = jiffies; | ||
328 | rec->lastbytetime = jiffies; | ||
329 | #endif | ||
330 | /* copy bytes from intermediate buffer position sw_data to the | ||
331 | * HW and return number of bytes actually written | ||
332 | * Furthermore, set hw_ready to 0, if the fifo isn't empty | ||
333 | * now => more could be transfered to fifo | ||
334 | */ | ||
335 | bytes = copy(substream, rec, bytes); | ||
336 | rec->bytes2hw += bytes; | ||
337 | |||
338 | #ifdef SND_PCM_INDIRECT2_STAT | ||
339 | if (bytes < 64) | ||
340 | rec->byte_sizes[bytes]++; | ||
341 | else | ||
342 | snd_printk(KERN_DEBUG | ||
343 | "STAT: %d Bytes copied to hardware at once " | ||
344 | "- too big to save!\n", | ||
345 | bytes); | ||
346 | #endif | ||
347 | /* increase sw_data by the number of actually written bytes | ||
348 | * (= number of taken bytes from intermediate buffer) | ||
349 | */ | ||
350 | rec->sw_data += bytes; | ||
351 | if (rec->sw_data == rec->sw_buffer_size) | ||
352 | rec->sw_data = 0; | ||
353 | /* now sw_data is the position where ALSA is going to write | ||
354 | * in the intermediate buffer next time = position we are going | ||
355 | * to read from next time | ||
356 | */ | ||
357 | |||
358 | snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 1, | ||
359 | bytes); | ||
360 | |||
361 | /* we read bytes from intermediate buffer, so we need to say | ||
362 | * that the number of bytes ready for transfer are decreased | ||
363 | * now | ||
364 | */ | ||
365 | rec->sw_ready -= bytes; | ||
366 | } | ||
367 | return; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * helper function for playback interrupt routine | ||
372 | */ | ||
373 | void | ||
374 | snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream, | ||
375 | struct snd_pcm_indirect2 *rec, | ||
376 | snd_pcm_indirect2_copy_t copy, | ||
377 | snd_pcm_indirect2_zero_t zero) | ||
378 | { | ||
379 | #ifdef SND_PCM_INDIRECT2_STAT | ||
380 | rec->irq_occured++; | ||
381 | #endif | ||
382 | /* hardware played some bytes, so there is room again (in fifo) */ | ||
383 | rec->hw_ready = 1; | ||
384 | |||
385 | /* don't call ack() now, instead call transfer() function directly | ||
386 | * (normally called by ack() ) | ||
387 | */ | ||
388 | snd_pcm_indirect2_playback_transfer(substream, rec, copy, zero); | ||
389 | |||
390 | if (rec->min_periods >= rec->min_multiple) { | ||
391 | #ifdef SND_PCM_INDIRECT2_STAT | ||
392 | if ((rec->min_periods / rec->min_multiple) > 7) | ||
393 | snd_printk(KERN_DEBUG | ||
394 | "STAT: more than 7 (%d) mul_adds - too big " | ||
395 | "to save!\n", | ||
396 | (rec->min_periods / rec->min_multiple)); | ||
397 | else | ||
398 | rec->mul_adds[(rec->min_periods / | ||
399 | rec->min_multiple)]++; | ||
400 | rec->mul_elapsed_real += (rec->min_periods / | ||
401 | rec->min_multiple); | ||
402 | rec->mul_elapsed++; | ||
403 | #endif | ||
404 | rec->min_periods = (rec->min_periods % rec->min_multiple); | ||
405 | snd_pcm_period_elapsed(substream); | ||
406 | } | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * _internal_ helper function for capture interrupt callback | ||
411 | */ | ||
412 | static void | ||
413 | snd_pcm_indirect2_capture_transfer(struct snd_pcm_substream *substream, | ||
414 | struct snd_pcm_indirect2 *rec, | ||
415 | snd_pcm_indirect2_copy_t copy, | ||
416 | snd_pcm_indirect2_zero_t null) | ||
417 | { | ||
418 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
419 | snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; | ||
420 | snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr; | ||
421 | |||
422 | if (diff) { | ||
423 | #ifdef SND_PCM_INDIRECT2_STAT | ||
424 | rec->lastdifftime = jiffies; | ||
425 | #endif | ||
426 | if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) | ||
427 | diff += runtime->boundary; | ||
428 | rec->sw_ready -= frames_to_bytes(runtime, diff); | ||
429 | rec->appl_ptr = appl_ptr; | ||
430 | } | ||
431 | /* if hardware has something, but the intermediate buffer is full | ||
432 | * => skip contents of buffer | ||
433 | */ | ||
434 | if (rec->hw_ready && (rec->sw_ready >= (int)rec->sw_buffer_size)) { | ||
435 | unsigned int bytes; | ||
436 | |||
437 | #ifdef SND_PCM_INDIRECT2_STAT | ||
438 | if (rec->firstzerotime == 0) { | ||
439 | rec->firstzerotime = jiffies; | ||
440 | snd_printk(KERN_DEBUG "STAT: (capture) " | ||
441 | "@firstzerotime: mul_elapsed: %d, " | ||
442 | "min_period_count: %d\n", | ||
443 | rec->mul_elapsed, rec->min_period_count); | ||
444 | snd_printk(KERN_DEBUG "STAT: (capture) " | ||
445 | "@firstzerotime: sw_io: %d, sw_data: %d, " | ||
446 | "appl_ptr: %u\n", | ||
447 | rec->sw_io, rec->sw_data, | ||
448 | (unsigned int)appl_ptr); | ||
449 | } | ||
450 | if ((jiffies - rec->firstzerotime) < 3750) { | ||
451 | rec->zero_times[(jiffies - rec->firstzerotime)]++; | ||
452 | rec->zero_times_saved++; | ||
453 | } else | ||
454 | rec->zero_times_notsaved++; | ||
455 | #endif | ||
456 | bytes = null(substream, rec); | ||
457 | |||
458 | #ifdef SND_PCM_INDIRECT2_STAT | ||
459 | rec->zeros2hw += bytes; | ||
460 | if (bytes < 64) | ||
461 | rec->zero_sizes[bytes]++; | ||
462 | else | ||
463 | snd_printk(KERN_DEBUG | ||
464 | "STAT: (capture) %d zero Bytes copied to " | ||
465 | "hardware at once - too big to save!\n", | ||
466 | bytes); | ||
467 | #endif | ||
468 | snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 0, | ||
469 | bytes); | ||
470 | /* report an overrun */ | ||
471 | rec->sw_io = SNDRV_PCM_POS_XRUN; | ||
472 | return; | ||
473 | } | ||
474 | while (rec->hw_ready && (rec->sw_ready < (int)rec->sw_buffer_size)) { | ||
475 | /* sw_to_end: max. number of bytes that we can write to the | ||
476 | * intermediate buffer (until it's end) | ||
477 | */ | ||
478 | size_t sw_to_end = rec->sw_buffer_size - rec->sw_data; | ||
479 | |||
480 | /* bytes: max. number of bytes, which may be copied to the | ||
481 | * intermediate buffer without overflow (in _one_ step) | ||
482 | */ | ||
483 | size_t bytes = rec->sw_buffer_size - rec->sw_ready; | ||
484 | |||
485 | /* limit number of bytes (for transfer) by available room in | ||
486 | * the intermediate buffer | ||
487 | */ | ||
488 | if (sw_to_end < bytes) | ||
489 | bytes = sw_to_end; | ||
490 | if (!bytes) | ||
491 | break; | ||
492 | |||
493 | #ifdef SND_PCM_INDIRECT2_STAT | ||
494 | if (rec->firstbytetime == 0) | ||
495 | rec->firstbytetime = jiffies; | ||
496 | rec->lastbytetime = jiffies; | ||
497 | #endif | ||
498 | /* copy bytes from the intermediate buffer (position sw_data) | ||
499 | * to the HW at most and return number of bytes actually copied | ||
500 | * from HW | ||
501 | * Furthermore, set hw_ready to 0, if the fifo is empty now. | ||
502 | */ | ||
503 | bytes = copy(substream, rec, bytes); | ||
504 | rec->bytes2hw += bytes; | ||
505 | |||
506 | #ifdef SND_PCM_INDIRECT2_STAT | ||
507 | if (bytes < 64) | ||
508 | rec->byte_sizes[bytes]++; | ||
509 | else | ||
510 | snd_printk(KERN_DEBUG | ||
511 | "STAT: (capture) %d Bytes copied to " | ||
512 | "hardware at once - too big to save!\n", | ||
513 | bytes); | ||
514 | #endif | ||
515 | /* increase sw_data by the number of actually copied bytes from | ||
516 | * HW | ||
517 | */ | ||
518 | rec->sw_data += bytes; | ||
519 | if (rec->sw_data == rec->sw_buffer_size) | ||
520 | rec->sw_data = 0; | ||
521 | |||
522 | snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 1, | ||
523 | bytes); | ||
524 | |||
525 | /* number of bytes in the intermediate buffer, which haven't | ||
526 | * been fetched by ALSA yet. | ||
527 | */ | ||
528 | rec->sw_ready += bytes; | ||
529 | } | ||
530 | return; | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * helper function for capture interrupt routine | ||
535 | */ | ||
536 | void | ||
537 | snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream, | ||
538 | struct snd_pcm_indirect2 *rec, | ||
539 | snd_pcm_indirect2_copy_t copy, | ||
540 | snd_pcm_indirect2_zero_t null) | ||
541 | { | ||
542 | #ifdef SND_PCM_INDIRECT2_STAT | ||
543 | rec->irq_occured++; | ||
544 | #endif | ||
545 | /* hardware recorded some bytes, so there is something to read from the | ||
546 | * record fifo: | ||
547 | */ | ||
548 | rec->hw_ready = 1; | ||
549 | |||
550 | /* don't call ack() now, instead call transfer() function directly | ||
551 | * (normally called by ack() ) | ||
552 | */ | ||
553 | snd_pcm_indirect2_capture_transfer(substream, rec, copy, null); | ||
554 | |||
555 | if (rec->min_periods >= rec->min_multiple) { | ||
556 | |||
557 | #ifdef SND_PCM_INDIRECT2_STAT | ||
558 | if ((rec->min_periods / rec->min_multiple) > 7) | ||
559 | snd_printk(KERN_DEBUG | ||
560 | "STAT: more than 7 (%d) mul_adds - " | ||
561 | "too big to save!\n", | ||
562 | (rec->min_periods / rec->min_multiple)); | ||
563 | else | ||
564 | rec->mul_adds[(rec->min_periods / | ||
565 | rec->min_multiple)]++; | ||
566 | rec->mul_elapsed_real += (rec->min_periods / | ||
567 | rec->min_multiple); | ||
568 | rec->mul_elapsed++; | ||
569 | #endif | ||
570 | rec->min_periods = (rec->min_periods % rec->min_multiple); | ||
571 | snd_pcm_period_elapsed(substream); | ||
572 | } | ||
573 | } | ||
diff --git a/sound/drivers/pcm-indirect2.h b/sound/drivers/pcm-indirect2.h new file mode 100644 index 000000000000..2ea6e460f348 --- /dev/null +++ b/sound/drivers/pcm-indirect2.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Helper functions for indirect PCM data transfer to a simple FIFO in | ||
3 | * hardware (small, no possibility to read "hardware io position", | ||
4 | * updating position done by interrupt, ...) | ||
5 | * | ||
6 | * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> | ||
7 | * | ||
8 | * Based on "pcm-indirect.h" (alsa-driver-1.0.13) by | ||
9 | * | ||
10 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
11 | * Jaroslav Kysela <perex@suse.cz> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #ifndef __SOUND_PCM_INDIRECT2_H | ||
29 | #define __SOUND_PCM_INDIRECT2_H | ||
30 | |||
31 | /* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t */ | ||
32 | #include <sound/pcm.h> | ||
33 | |||
34 | /* Debug options for code which may be removed completely in a final version */ | ||
35 | #ifdef CONFIG_SND_DEBUG | ||
36 | #define SND_PCM_INDIRECT2_STAT /* turn on some "statistics" about the | ||
37 | * process of copying bytes from the | ||
38 | * intermediate buffer to the hardware | ||
39 | * fifo and the other way round | ||
40 | */ | ||
41 | #endif | ||
42 | |||
43 | struct snd_pcm_indirect2 { | ||
44 | unsigned int hw_buffer_size; /* Byte size of hardware buffer */ | ||
45 | int hw_ready; /* playback: 1 = hw fifo has room left, | ||
46 | * 0 = hw fifo is full | ||
47 | */ | ||
48 | unsigned int min_multiple; | ||
49 | int min_periods; /* counts number of min. periods until | ||
50 | * min_multiple is reached | ||
51 | */ | ||
52 | int min_period_count; /* counts bytes to count number of | ||
53 | * min. periods | ||
54 | */ | ||
55 | |||
56 | unsigned int sw_buffer_size; /* Byte size of software buffer */ | ||
57 | |||
58 | /* sw_data: position in intermediate buffer, where we will read (or | ||
59 | * write) from/to next time (to transfer data to/from HW) | ||
60 | */ | ||
61 | unsigned int sw_data; /* Offset to next dst (or src) in sw | ||
62 | * ring buffer | ||
63 | */ | ||
64 | /* easiest case (playback): | ||
65 | * sw_data is nearly the same as ~ runtime->control->appl_ptr, with the | ||
66 | * exception that sw_data is "behind" by the number if bytes ALSA wrote | ||
67 | * to the intermediate buffer last time. | ||
68 | * A call to ack() callback synchronizes both indirectly. | ||
69 | */ | ||
70 | |||
71 | /* We have no real sw_io pointer here. Usually sw_io is pointing to the | ||
72 | * current playback/capture position _inside_ the hardware. Devices | ||
73 | * with plain FIFOs often have no possibility to publish this position. | ||
74 | * So we say: if sw_data is updated, that means bytes were copied to | ||
75 | * the hardware, we increase sw_io by that amount, because there have | ||
76 | * to be as much bytes which were played. So sw_io will stay behind | ||
77 | * sw_data all the time and has to converge to sw_data at the end of | ||
78 | * playback. | ||
79 | */ | ||
80 | unsigned int sw_io; /* Current software pointer in bytes */ | ||
81 | |||
82 | /* sw_ready: number of bytes ALSA copied to the intermediate buffer, so | ||
83 | * it represents the number of bytes which wait for transfer to the HW | ||
84 | */ | ||
85 | int sw_ready; /* Bytes ready to be transferred to/from hw */ | ||
86 | |||
87 | /* appl_ptr: last known position of ALSA (where ALSA is going to write | ||
88 | * next time into the intermediate buffer | ||
89 | */ | ||
90 | snd_pcm_uframes_t appl_ptr; /* Last seen appl_ptr */ | ||
91 | |||
92 | unsigned int bytes2hw; | ||
93 | int check_alignment; | ||
94 | |||
95 | #ifdef SND_PCM_INDIRECT2_STAT | ||
96 | unsigned int zeros2hw; | ||
97 | unsigned int mul_elapsed; | ||
98 | unsigned int mul_elapsed_real; | ||
99 | unsigned long firstbytetime; | ||
100 | unsigned long lastbytetime; | ||
101 | unsigned long firstzerotime; | ||
102 | unsigned int byte_sizes[64]; | ||
103 | unsigned int zero_sizes[64]; | ||
104 | unsigned int min_adds[8]; | ||
105 | unsigned int mul_adds[8]; | ||
106 | unsigned int zero_times[3750]; /* = 15s */ | ||
107 | unsigned int zero_times_saved; | ||
108 | unsigned int zero_times_notsaved; | ||
109 | unsigned int irq_occured; | ||
110 | unsigned int pointer_calls; | ||
111 | unsigned int lastdifftime; | ||
112 | #endif | ||
113 | }; | ||
114 | |||
115 | typedef size_t (*snd_pcm_indirect2_copy_t) (struct snd_pcm_substream *substream, | ||
116 | struct snd_pcm_indirect2 *rec, | ||
117 | size_t bytes); | ||
118 | typedef size_t (*snd_pcm_indirect2_zero_t) (struct snd_pcm_substream *substream, | ||
119 | struct snd_pcm_indirect2 *rec); | ||
120 | |||
121 | #ifdef SND_PCM_INDIRECT2_STAT | ||
122 | void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream, | ||
123 | struct snd_pcm_indirect2 *rec); | ||
124 | #endif | ||
125 | |||
126 | snd_pcm_uframes_t | ||
127 | snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream, | ||
128 | struct snd_pcm_indirect2 *rec); | ||
129 | void | ||
130 | snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream, | ||
131 | struct snd_pcm_indirect2 *rec, | ||
132 | snd_pcm_indirect2_copy_t copy, | ||
133 | snd_pcm_indirect2_zero_t zero); | ||
134 | void | ||
135 | snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream, | ||
136 | struct snd_pcm_indirect2 *rec, | ||
137 | snd_pcm_indirect2_copy_t copy, | ||
138 | snd_pcm_indirect2_zero_t null); | ||
139 | |||
140 | #endif /* __SOUND_PCM_INDIRECT2_H */ | ||
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 1b832870cc84..b1c047ec19af 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c | |||
@@ -37,7 +37,6 @@ | |||
37 | * - ported from alsa 0.5 to 1.0 | 37 | * - ported from alsa 0.5 to 1.0 |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include <sound/driver.h> | ||
41 | #include <linux/init.h> | 40 | #include <linux/init.h> |
42 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
43 | #include <linux/parport.h> | 42 | #include <linux/parport.h> |
@@ -797,6 +796,8 @@ static int __devinit snd_portman_probe(struct platform_device *pdev) | |||
797 | 796 | ||
798 | platform_set_drvdata(pdev, card); | 797 | platform_set_drvdata(pdev, card); |
799 | 798 | ||
799 | snd_card_set_dev(card, &pdev->dev); | ||
800 | |||
800 | /* At this point card will be usable */ | 801 | /* At this point card will be usable */ |
801 | if ((err = snd_card_register(card)) < 0) { | 802 | if ((err = snd_card_register(card)) < 0) { |
802 | snd_printd("Cannot register card\n"); | 803 | snd_printd("Cannot register card\n"); |
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 65de3a755ddb..d8aab9da97c2 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * More documentation can be found in serial-u16550.txt. | 30 | * More documentation can be found in serial-u16550.txt. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <linux/init.h> | 33 | #include <linux/init.h> |
35 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
36 | #include <linux/err.h> | 35 | #include <linux/err.h> |
@@ -43,6 +42,7 @@ | |||
43 | #include <sound/initval.h> | 42 | #include <sound/initval.h> |
44 | 43 | ||
45 | #include <linux/serial_reg.h> | 44 | #include <linux/serial_reg.h> |
45 | #include <linux/jiffies.h> | ||
46 | 46 | ||
47 | #include <asm/io.h> | 47 | #include <asm/io.h> |
48 | 48 | ||
@@ -455,7 +455,7 @@ static void snd_uart16550_do_open(struct snd_uart16550 * uart) | |||
455 | | UART_IER_THRI /* Enable Transmitter holding register empty interrupt */ | 455 | | UART_IER_THRI /* Enable Transmitter holding register empty interrupt */ |
456 | ; | 456 | ; |
457 | } | 457 | } |
458 | outb(byte, uart->base + UART_IER); /* Interupt enable Register */ | 458 | outb(byte, uart->base + UART_IER); /* Interrupt enable Register */ |
459 | 459 | ||
460 | inb(uart->base + UART_LSR); /* Clear any pre-existing overrun indication */ | 460 | inb(uart->base + UART_LSR); /* Clear any pre-existing overrun indication */ |
461 | inb(uart->base + UART_IIR); /* Clear any pre-existing transmit interrupt */ | 461 | inb(uart->base + UART_IIR); /* Clear any pre-existing transmit interrupt */ |
@@ -473,7 +473,7 @@ static void snd_uart16550_do_close(struct snd_uart16550 * uart) | |||
473 | 473 | ||
474 | outb((0 & UART_IER_RDI) /* Disable Receiver data interrupt */ | 474 | outb((0 & UART_IER_RDI) /* Disable Receiver data interrupt */ |
475 | |(0 & UART_IER_THRI) /* Disable Transmitter holding register empty interrupt */ | 475 | |(0 & UART_IER_THRI) /* Disable Transmitter holding register empty interrupt */ |
476 | ,uart->base + UART_IER); /* Interupt enable Register */ | 476 | ,uart->base + UART_IER); /* Interrupt enable Register */ |
477 | 477 | ||
478 | switch (uart->adaptor) { | 478 | switch (uart->adaptor) { |
479 | default: | 479 | default: |
@@ -653,7 +653,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
653 | char first; | 653 | char first; |
654 | static unsigned long lasttime = 0; | 654 | static unsigned long lasttime = 0; |
655 | 655 | ||
656 | /* Interupts are disabled during the updating of the tx_buff, | 656 | /* Interrupts are disabled during the updating of the tx_buff, |
657 | * since it is 'bad' to have two processes updating the same | 657 | * since it is 'bad' to have two processes updating the same |
658 | * variables (ie buff_in & buff_out) | 658 | * variables (ie buff_in & buff_out) |
659 | */ | 659 | */ |
@@ -694,7 +694,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
694 | (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || | 694 | (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || |
695 | uart->adaptor == SNDRV_SERIAL_GENERIC) && | 695 | uart->adaptor == SNDRV_SERIAL_GENERIC) && |
696 | (uart->prev_out != substream->number || | 696 | (uart->prev_out != substream->number || |
697 | jiffies-lasttime > 3*HZ)) { | 697 | time_after(jiffies, lasttime + 3*HZ))) { |
698 | 698 | ||
699 | if (snd_uart16550_buffer_can_write(uart, 3)) { | 699 | if (snd_uart16550_buffer_can_write(uart, 3)) { |
700 | /* Roland Soundcanvas part selection */ | 700 | /* Roland Soundcanvas part selection */ |
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 915c86773c21..f79e3614079d 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c | |||
@@ -41,7 +41,6 @@ | |||
41 | * - Run application using a midi device (eg. /dev/snd/midiC1D0) | 41 | * - Run application using a midi device (eg. /dev/snd/midiC1D0) |
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include <sound/driver.h> | ||
45 | #include <linux/init.h> | 44 | #include <linux/init.h> |
46 | #include <linux/wait.h> | 45 | #include <linux/wait.h> |
47 | #include <linux/err.h> | 46 | #include <linux/err.h> |
diff --git a/sound/drivers/vx/vx_cmd.c b/sound/drivers/vx/vx_cmd.c index 7a221349f285..9529e3bf2866 100644 --- a/sound/drivers/vx/vx_cmd.c +++ b/sound/drivers/vx/vx_cmd.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
26 | #include <sound/vx_core.h> | 25 | #include <sound/vx_core.h> |
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index ed19bc17400b..99538862e342 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c index 9a8154c9416e..1dfe6948e6ff 100644 --- a/sound/drivers/vx/vx_hwdep.c +++ b/sound/drivers/vx/vx_hwdep.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/device.h> | 23 | #include <linux/device.h> |
25 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
26 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index b8fcd79a7e11..5a347321f8c0 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/control.h> | 24 | #include <sound/control.h> |
26 | #include <sound/tlv.h> | 25 | #include <sound/tlv.h> |
@@ -439,14 +438,19 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
439 | { | 438 | { |
440 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 439 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
441 | int codec = kcontrol->id.index; | 440 | int codec = kcontrol->id.index; |
441 | unsigned int val[2], vmax; | ||
442 | |||
443 | vmax = chip->hw->output_level_max; | ||
444 | val[0] = ucontrol->value.integer.value[0]; | ||
445 | val[1] = ucontrol->value.integer.value[1]; | ||
446 | if (val[0] > vmax || val[1] > vmax) | ||
447 | return -EINVAL; | ||
442 | mutex_lock(&chip->mixer_mutex); | 448 | mutex_lock(&chip->mixer_mutex); |
443 | if (ucontrol->value.integer.value[0] != chip->output_level[codec][0] || | 449 | if (val[0] != chip->output_level[codec][0] || |
444 | ucontrol->value.integer.value[1] != chip->output_level[codec][1]) { | 450 | val[1] != chip->output_level[codec][1]) { |
445 | vx_set_analog_output_level(chip, codec, | 451 | vx_set_analog_output_level(chip, codec, val[0], val[1]); |
446 | ucontrol->value.integer.value[0], | 452 | chip->output_level[codec][0] = val[0]; |
447 | ucontrol->value.integer.value[1]); | 453 | chip->output_level[codec][1] = val[1]; |
448 | chip->output_level[codec][0] = ucontrol->value.integer.value[0]; | ||
449 | chip->output_level[codec][1] = ucontrol->value.integer.value[1]; | ||
450 | mutex_unlock(&chip->mixer_mutex); | 454 | mutex_unlock(&chip->mixer_mutex); |
451 | return 1; | 455 | return 1; |
452 | } | 456 | } |
@@ -506,6 +510,14 @@ static int vx_audio_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
506 | static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 510 | static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
507 | { | 511 | { |
508 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 512 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
513 | |||
514 | if (chip->type >= VX_TYPE_VXPOCKET) { | ||
515 | if (ucontrol->value.enumerated.item[0] > 2) | ||
516 | return -EINVAL; | ||
517 | } else { | ||
518 | if (ucontrol->value.enumerated.item[0] > 1) | ||
519 | return -EINVAL; | ||
520 | } | ||
509 | mutex_lock(&chip->mixer_mutex); | 521 | mutex_lock(&chip->mixer_mutex); |
510 | if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) { | 522 | if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) { |
511 | chip->audio_source_target = ucontrol->value.enumerated.item[0]; | 523 | chip->audio_source_target = ucontrol->value.enumerated.item[0]; |
@@ -554,6 +566,9 @@ static int vx_clock_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
554 | static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 566 | static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
555 | { | 567 | { |
556 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 568 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
569 | |||
570 | if (ucontrol->value.enumerated.item[0] > 2) | ||
571 | return -EINVAL; | ||
557 | mutex_lock(&chip->mixer_mutex); | 572 | mutex_lock(&chip->mixer_mutex); |
558 | if (chip->clock_mode != ucontrol->value.enumerated.item[0]) { | 573 | if (chip->clock_mode != ucontrol->value.enumerated.item[0]) { |
559 | chip->clock_mode = ucontrol->value.enumerated.item[0]; | 574 | chip->clock_mode = ucontrol->value.enumerated.item[0]; |
@@ -603,12 +618,17 @@ static int vx_audio_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
603 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 618 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
604 | int audio = kcontrol->private_value & 0xff; | 619 | int audio = kcontrol->private_value & 0xff; |
605 | int capture = (kcontrol->private_value >> 8) & 1; | 620 | int capture = (kcontrol->private_value >> 8) & 1; |
621 | unsigned int val[2]; | ||
606 | 622 | ||
623 | val[0] = ucontrol->value.integer.value[0]; | ||
624 | val[1] = ucontrol->value.integer.value[1]; | ||
625 | if (val[0] > CVAL_MAX || val[1] > CVAL_MAX) | ||
626 | return -EINVAL; | ||
607 | mutex_lock(&chip->mixer_mutex); | 627 | mutex_lock(&chip->mixer_mutex); |
608 | if (ucontrol->value.integer.value[0] != chip->audio_gain[capture][audio] || | 628 | if (val[0] != chip->audio_gain[capture][audio] || |
609 | ucontrol->value.integer.value[1] != chip->audio_gain[capture][audio+1]) { | 629 | val[1] != chip->audio_gain[capture][audio+1]) { |
610 | vx_set_audio_gain(chip, audio, capture, ucontrol->value.integer.value[0]); | 630 | vx_set_audio_gain(chip, audio, capture, val[0]); |
611 | vx_set_audio_gain(chip, audio+1, capture, ucontrol->value.integer.value[1]); | 631 | vx_set_audio_gain(chip, audio+1, capture, val[1]); |
612 | mutex_unlock(&chip->mixer_mutex); | 632 | mutex_unlock(&chip->mixer_mutex); |
613 | return 1; | 633 | return 1; |
614 | } | 634 | } |
@@ -632,13 +652,19 @@ static int vx_audio_monitor_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
632 | { | 652 | { |
633 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 653 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
634 | int audio = kcontrol->private_value & 0xff; | 654 | int audio = kcontrol->private_value & 0xff; |
655 | unsigned int val[2]; | ||
656 | |||
657 | val[0] = ucontrol->value.integer.value[0]; | ||
658 | val[1] = ucontrol->value.integer.value[1]; | ||
659 | if (val[0] > CVAL_MAX || val[1] > CVAL_MAX) | ||
660 | return -EINVAL; | ||
635 | 661 | ||
636 | mutex_lock(&chip->mixer_mutex); | 662 | mutex_lock(&chip->mixer_mutex); |
637 | if (ucontrol->value.integer.value[0] != chip->audio_monitor[audio] || | 663 | if (val[0] != chip->audio_monitor[audio] || |
638 | ucontrol->value.integer.value[1] != chip->audio_monitor[audio+1]) { | 664 | val[1] != chip->audio_monitor[audio+1]) { |
639 | vx_set_monitor_level(chip, audio, ucontrol->value.integer.value[0], | 665 | vx_set_monitor_level(chip, audio, val[0], |
640 | chip->audio_monitor_active[audio]); | 666 | chip->audio_monitor_active[audio]); |
641 | vx_set_monitor_level(chip, audio+1, ucontrol->value.integer.value[1], | 667 | vx_set_monitor_level(chip, audio+1, val[1], |
642 | chip->audio_monitor_active[audio+1]); | 668 | chip->audio_monitor_active[audio+1]); |
643 | mutex_unlock(&chip->mixer_mutex); | 669 | mutex_unlock(&chip->mixer_mutex); |
644 | return 1; | 670 | return 1; |
@@ -669,8 +695,10 @@ static int vx_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va | |||
669 | mutex_lock(&chip->mixer_mutex); | 695 | mutex_lock(&chip->mixer_mutex); |
670 | if (ucontrol->value.integer.value[0] != chip->audio_active[audio] || | 696 | if (ucontrol->value.integer.value[0] != chip->audio_active[audio] || |
671 | ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) { | 697 | ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) { |
672 | vx_set_audio_switch(chip, audio, ucontrol->value.integer.value[0]); | 698 | vx_set_audio_switch(chip, audio, |
673 | vx_set_audio_switch(chip, audio+1, ucontrol->value.integer.value[1]); | 699 | !!ucontrol->value.integer.value[0]); |
700 | vx_set_audio_switch(chip, audio+1, | ||
701 | !!ucontrol->value.integer.value[1]); | ||
674 | mutex_unlock(&chip->mixer_mutex); | 702 | mutex_unlock(&chip->mixer_mutex); |
675 | return 1; | 703 | return 1; |
676 | } | 704 | } |
@@ -699,9 +727,9 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
699 | if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] || | 727 | if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] || |
700 | ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) { | 728 | ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) { |
701 | vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], | 729 | vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], |
702 | ucontrol->value.integer.value[0]); | 730 | !!ucontrol->value.integer.value[0]); |
703 | vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], | 731 | vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], |
704 | ucontrol->value.integer.value[1]); | 732 | !!ucontrol->value.integer.value[1]); |
705 | mutex_unlock(&chip->mixer_mutex); | 733 | mutex_unlock(&chip->mixer_mutex); |
706 | return 1; | 734 | return 1; |
707 | } | 735 | } |
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 7e65a103fbb2..fdbf86571b1f 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c | |||
@@ -45,7 +45,6 @@ | |||
45 | * - scheduled action on the stream. | 45 | * - scheduled action on the stream. |
46 | */ | 46 | */ |
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
50 | #include <linux/vmalloc.h> | 49 | #include <linux/vmalloc.h> |
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c index 7400306b7f28..fb8932af888d 100644 --- a/sound/drivers/vx/vx_uer.c +++ b/sound/drivers/vx/vx_uer.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
26 | #include <sound/vx_core.h> | 25 | #include <sound/vx_core.h> |