diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-20 12:41:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-20 12:41:44 -0400 |
commit | 7f06a8b26aba1dc03b42272dc0089a800372c575 (patch) | |
tree | 7c67198f83d069eb13fd417e022d111b7e4c82a1 /sound/pci | |
parent | c3ad33c9bcb6616999953af76f16318120fe3691 (diff) | |
parent | d71f4cece4bd97d05592836202fc04ff2e7817e3 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (250 commits)
ALSA: hda: Storage class should be before const qualifier
ASoC: tpa6130a2: Remove CPVSS and HPVdd supplies
ASoC: tpa6130a2: Define output pins with SND_SOC_DAPM_OUTPUT
ASoC: sdp4430 - add sdp4430 pcm ops to DAI.
ASoC: TWL6040: Enable earphone path in codec
ASoC: SDP4430: Add support for Earphone speaker
ASoC: SDP4430: Add sdp4430 machine driver
ASoC: tlv320dac33: Avoid powering off while in BIAS_OFF
ASoC: tlv320dac33: Use dev_dbg in dac33_hard_power function
ALSA: sound/pci/asihpi: Use kzalloc
ALSA: hdmi - dont fail on extra nodes
ALSA: intelhdmi - add id for the CougarPoint chipset
ALSA: intelhdmi - user friendly codec name
ALSA: intelhdmi - add dependency on SND_DYNAMIC_MINORS
ALSA: asihpi: incorrect range check
ALSA: asihpi: testing the wrong variable
ALSA: es1688: add pedantic range checks
ARM: McBSP: Add support for omap4 in McBSP driver
ARM: McBSP: Fix request for irq in OMAP4
OMAP: McBSP: Add 32-bit mode support
...
Diffstat (limited to 'sound/pci')
42 files changed, 19305 insertions, 314 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 1298c68d6bf..e7a8cd058ef 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -58,6 +58,18 @@ config SND_ALI5451 | |||
58 | To compile this driver as a module, choose M here: the module | 58 | To compile this driver as a module, choose M here: the module |
59 | will be called snd-ali5451. | 59 | will be called snd-ali5451. |
60 | 60 | ||
61 | config SND_ASIHPI | ||
62 | tristate "AudioScience ASIxxxx" | ||
63 | depends on X86 | ||
64 | select FW_LOADER | ||
65 | select SND_PCM | ||
66 | select SND_HWDEP | ||
67 | help | ||
68 | Say Y here to include support for AudioScience ASI sound cards. | ||
69 | |||
70 | To compile this driver as a module, choose M here: the module | ||
71 | will be called snd-asihpi. | ||
72 | |||
61 | config SND_ATIIXP | 73 | config SND_ATIIXP |
62 | tristate "ATI IXP AC97 Controller" | 74 | tristate "ATI IXP AC97 Controller" |
63 | select SND_AC97_CODEC | 75 | select SND_AC97_CODEC |
@@ -501,6 +513,16 @@ config SND_ES1968 | |||
501 | To compile this driver as a module, choose M here: the module | 513 | To compile this driver as a module, choose M here: the module |
502 | will be called snd-es1968. | 514 | will be called snd-es1968. |
503 | 515 | ||
516 | config SND_ES1968_INPUT | ||
517 | bool "Enable input device for es1968 volume buttons" | ||
518 | depends on SND_ES1968 | ||
519 | depends on INPUT=y || INPUT=SND_ES1968 | ||
520 | help | ||
521 | If you say Y here, you will get an input device which reports | ||
522 | keypresses for the volume buttons connected to the es1968 chip. | ||
523 | If you say N the buttons will directly control the master volume. | ||
524 | It is recommended to say Y. | ||
525 | |||
504 | config SND_FM801 | 526 | config SND_FM801 |
505 | tristate "ForteMedia FM801" | 527 | tristate "ForteMedia FM801" |
506 | select SND_OPL3_LIB | 528 | select SND_OPL3_LIB |
@@ -655,6 +677,16 @@ config SND_MAESTRO3 | |||
655 | To compile this driver as a module, choose M here: the module | 677 | To compile this driver as a module, choose M here: the module |
656 | will be called snd-maestro3. | 678 | will be called snd-maestro3. |
657 | 679 | ||
680 | config SND_MAESTRO3_INPUT | ||
681 | bool "Enable input device for maestro3 volume buttons" | ||
682 | depends on SND_MAESTRO3 | ||
683 | depends on INPUT=y || INPUT=SND_MAESTRO3 | ||
684 | help | ||
685 | If you say Y here, you will get an input device which reports | ||
686 | keypresses for the volume buttons connected to the maestro3 chip. | ||
687 | If you say N the buttons will directly control the master volume. | ||
688 | It is recommended to say Y. | ||
689 | |||
658 | config SND_MIXART | 690 | config SND_MIXART |
659 | tristate "Digigram miXart" | 691 | tristate "Digigram miXart" |
660 | select SND_HWDEP | 692 | select SND_HWDEP |
diff --git a/sound/pci/Makefile b/sound/pci/Makefile index ecfc609d2b9..9cf4348ec13 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile | |||
@@ -57,6 +57,7 @@ obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o | |||
57 | obj-$(CONFIG_SND) += \ | 57 | obj-$(CONFIG_SND) += \ |
58 | ac97/ \ | 58 | ac97/ \ |
59 | ali5451/ \ | 59 | ali5451/ \ |
60 | asihpi/ \ | ||
60 | au88x0/ \ | 61 | au88x0/ \ |
61 | aw2/ \ | 62 | aw2/ \ |
62 | ctxfi/ \ | 63 | ctxfi/ \ |
diff --git a/sound/pci/asihpi/Makefile b/sound/pci/asihpi/Makefile new file mode 100644 index 00000000000..391830a4556 --- /dev/null +++ b/sound/pci/asihpi/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | snd-asihpi-objs := asihpi.o hpioctl.o hpimsginit.o\ | ||
2 | hpicmn.o hpifunc.o hpidebug.o hpidspcd.o\ | ||
3 | hpios.o hpi6000.o hpi6205.o hpimsgx.o | ||
4 | |||
5 | obj-$(CONFIG_SND_ASIHPI) += snd-asihpi.o | ||
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c new file mode 100644 index 00000000000..f74c7372b3d --- /dev/null +++ b/sound/pci/asihpi/asihpi.c | |||
@@ -0,0 +1,3002 @@ | |||
1 | /* | ||
2 | * Asihpi soundcard | ||
3 | * Copyright (c) by AudioScience Inc <alsa@audioscience.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation; | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * | ||
19 | * The following is not a condition of use, merely a request: | ||
20 | * If you modify this program, particularly if you fix errors, AudioScience Inc | ||
21 | * would appreciate it if you grant us the right to use those modifications | ||
22 | * for any purpose including commercial applications. | ||
23 | */ | ||
24 | /* >0: print Hw params, timer vars. >1: print stream write/copy sizes */ | ||
25 | #define REALLY_VERBOSE_LOGGING 0 | ||
26 | |||
27 | #if REALLY_VERBOSE_LOGGING | ||
28 | #define VPRINTK1 snd_printd | ||
29 | #else | ||
30 | #define VPRINTK1(...) | ||
31 | #endif | ||
32 | |||
33 | #if REALLY_VERBOSE_LOGGING > 1 | ||
34 | #define VPRINTK2 snd_printd | ||
35 | #else | ||
36 | #define VPRINTK2(...) | ||
37 | #endif | ||
38 | |||
39 | #ifndef ASI_STYLE_NAMES | ||
40 | /* not sure how ALSA style name should look */ | ||
41 | #define ASI_STYLE_NAMES 1 | ||
42 | #endif | ||
43 | |||
44 | #include "hpi_internal.h" | ||
45 | #include "hpimsginit.h" | ||
46 | #include "hpioctl.h" | ||
47 | |||
48 | #include <linux/pci.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/jiffies.h> | ||
51 | #include <linux/slab.h> | ||
52 | #include <linux/time.h> | ||
53 | #include <linux/wait.h> | ||
54 | #include <sound/core.h> | ||
55 | #include <sound/control.h> | ||
56 | #include <sound/pcm.h> | ||
57 | #include <sound/pcm_params.h> | ||
58 | #include <sound/info.h> | ||
59 | #include <sound/initval.h> | ||
60 | #include <sound/tlv.h> | ||
61 | #include <sound/hwdep.h> | ||
62 | |||
63 | |||
64 | MODULE_LICENSE("GPL"); | ||
65 | MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); | ||
66 | MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); | ||
67 | |||
68 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */ | ||
69 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
70 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
71 | static int enable_hpi_hwdep = 1; | ||
72 | |||
73 | module_param_array(index, int, NULL, S_IRUGO); | ||
74 | MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard."); | ||
75 | |||
76 | module_param_array(id, charp, NULL, S_IRUGO); | ||
77 | MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard."); | ||
78 | |||
79 | module_param_array(enable, bool, NULL, S_IRUGO); | ||
80 | MODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard."); | ||
81 | |||
82 | module_param(enable_hpi_hwdep, bool, S_IRUGO|S_IWUSR); | ||
83 | MODULE_PARM_DESC(enable_hpi_hwdep, | ||
84 | "ALSA enable HPI hwdep for AudioScience soundcard "); | ||
85 | |||
86 | /* identify driver */ | ||
87 | #ifdef KERNEL_ALSA_BUILD | ||
88 | static char *build_info = "built using headers from kernel source"; | ||
89 | module_param(build_info, charp, S_IRUGO); | ||
90 | MODULE_PARM_DESC(build_info, "built using headers from kernel source"); | ||
91 | #else | ||
92 | static char *build_info = "built within ALSA source"; | ||
93 | module_param(build_info, charp, S_IRUGO); | ||
94 | MODULE_PARM_DESC(build_info, "built within ALSA source"); | ||
95 | #endif | ||
96 | |||
97 | /* set to 1 to dump every control from adapter to log */ | ||
98 | static const int mixer_dump; | ||
99 | |||
100 | #define DEFAULT_SAMPLERATE 44100 | ||
101 | static int adapter_fs = DEFAULT_SAMPLERATE; | ||
102 | |||
103 | static struct hpi_hsubsys *ss; /* handle to HPI audio subsystem */ | ||
104 | |||
105 | /* defaults */ | ||
106 | #define PERIODS_MIN 2 | ||
107 | #define PERIOD_BYTES_MIN 2304 | ||
108 | #define BUFFER_BYTES_MAX (512 * 1024) | ||
109 | |||
110 | /*#define TIMER_MILLISECONDS 20 | ||
111 | #define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000) | ||
112 | */ | ||
113 | |||
114 | #define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7) | ||
115 | |||
116 | struct clk_source { | ||
117 | int source; | ||
118 | int index; | ||
119 | char *name; | ||
120 | }; | ||
121 | |||
122 | struct clk_cache { | ||
123 | int count; | ||
124 | int has_local; | ||
125 | struct clk_source s[MAX_CLOCKSOURCES]; | ||
126 | }; | ||
127 | |||
128 | /* Per card data */ | ||
129 | struct snd_card_asihpi { | ||
130 | struct snd_card *card; | ||
131 | struct pci_dev *pci; | ||
132 | u16 adapter_index; | ||
133 | u32 serial_number; | ||
134 | u16 type; | ||
135 | u16 version; | ||
136 | u16 num_outstreams; | ||
137 | u16 num_instreams; | ||
138 | |||
139 | u32 h_mixer; | ||
140 | struct clk_cache cc; | ||
141 | |||
142 | u16 support_mmap; | ||
143 | u16 support_grouping; | ||
144 | u16 support_mrx; | ||
145 | u16 update_interval_frames; | ||
146 | u16 in_max_chans; | ||
147 | u16 out_max_chans; | ||
148 | }; | ||
149 | |||
150 | /* Per stream data */ | ||
151 | struct snd_card_asihpi_pcm { | ||
152 | struct timer_list timer; | ||
153 | unsigned int respawn_timer; | ||
154 | unsigned int hpi_buffer_attached; | ||
155 | unsigned int pcm_size; | ||
156 | unsigned int pcm_count; | ||
157 | unsigned int bytes_per_sec; | ||
158 | unsigned int pcm_irq_pos; /* IRQ position */ | ||
159 | unsigned int pcm_buf_pos; /* position in buffer */ | ||
160 | struct snd_pcm_substream *substream; | ||
161 | u32 h_stream; | ||
162 | struct hpi_format format; | ||
163 | }; | ||
164 | |||
165 | /* universal stream verbs work with out or in stream handles */ | ||
166 | |||
167 | /* Functions to allow driver to give a buffer to HPI for busmastering */ | ||
168 | |||
169 | static u16 hpi_stream_host_buffer_attach( | ||
170 | struct hpi_hsubsys *hS, | ||
171 | u32 h_stream, /* handle to outstream. */ | ||
172 | u32 size_in_bytes, /* size in bytes of bus mastering buffer */ | ||
173 | u32 pci_address | ||
174 | ) | ||
175 | { | ||
176 | struct hpi_message hm; | ||
177 | struct hpi_response hr; | ||
178 | unsigned int obj = hpi_handle_object(h_stream); | ||
179 | |||
180 | if (!h_stream) | ||
181 | return HPI_ERROR_INVALID_OBJ; | ||
182 | hpi_init_message_response(&hm, &hr, obj, | ||
183 | obj == HPI_OBJ_OSTREAM ? | ||
184 | HPI_OSTREAM_HOSTBUFFER_ALLOC : | ||
185 | HPI_ISTREAM_HOSTBUFFER_ALLOC); | ||
186 | |||
187 | hpi_handle_to_indexes(h_stream, &hm.adapter_index, | ||
188 | &hm.obj_index); | ||
189 | |||
190 | hm.u.d.u.buffer.buffer_size = size_in_bytes; | ||
191 | hm.u.d.u.buffer.pci_address = pci_address; | ||
192 | hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER; | ||
193 | hpi_send_recv(&hm, &hr); | ||
194 | return hr.error; | ||
195 | } | ||
196 | |||
197 | static u16 hpi_stream_host_buffer_detach( | ||
198 | struct hpi_hsubsys *hS, | ||
199 | u32 h_stream | ||
200 | ) | ||
201 | { | ||
202 | struct hpi_message hm; | ||
203 | struct hpi_response hr; | ||
204 | unsigned int obj = hpi_handle_object(h_stream); | ||
205 | |||
206 | if (!h_stream) | ||
207 | return HPI_ERROR_INVALID_OBJ; | ||
208 | |||
209 | hpi_init_message_response(&hm, &hr, obj, | ||
210 | obj == HPI_OBJ_OSTREAM ? | ||
211 | HPI_OSTREAM_HOSTBUFFER_FREE : | ||
212 | HPI_ISTREAM_HOSTBUFFER_FREE); | ||
213 | |||
214 | hpi_handle_to_indexes(h_stream, &hm.adapter_index, | ||
215 | &hm.obj_index); | ||
216 | hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER; | ||
217 | hpi_send_recv(&hm, &hr); | ||
218 | return hr.error; | ||
219 | } | ||
220 | |||
221 | static inline u16 hpi_stream_start(struct hpi_hsubsys *hS, u32 h_stream) | ||
222 | { | ||
223 | if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) | ||
224 | return hpi_outstream_start(hS, h_stream); | ||
225 | else | ||
226 | return hpi_instream_start(hS, h_stream); | ||
227 | } | ||
228 | |||
229 | static inline u16 hpi_stream_stop(struct hpi_hsubsys *hS, u32 h_stream) | ||
230 | { | ||
231 | if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) | ||
232 | return hpi_outstream_stop(hS, h_stream); | ||
233 | else | ||
234 | return hpi_instream_stop(hS, h_stream); | ||
235 | } | ||
236 | |||
237 | static inline u16 hpi_stream_get_info_ex( | ||
238 | struct hpi_hsubsys *hS, | ||
239 | u32 h_stream, | ||
240 | u16 *pw_state, | ||
241 | u32 *pbuffer_size, | ||
242 | u32 *pdata_in_buffer, | ||
243 | u32 *psample_count, | ||
244 | u32 *pauxiliary_data | ||
245 | ) | ||
246 | { | ||
247 | if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) | ||
248 | return hpi_outstream_get_info_ex(hS, h_stream, pw_state, | ||
249 | pbuffer_size, pdata_in_buffer, | ||
250 | psample_count, pauxiliary_data); | ||
251 | else | ||
252 | return hpi_instream_get_info_ex(hS, h_stream, pw_state, | ||
253 | pbuffer_size, pdata_in_buffer, | ||
254 | psample_count, pauxiliary_data); | ||
255 | } | ||
256 | |||
257 | static inline u16 hpi_stream_group_add(struct hpi_hsubsys *hS, | ||
258 | u32 h_master, | ||
259 | u32 h_stream) | ||
260 | { | ||
261 | if (hpi_handle_object(h_master) == HPI_OBJ_OSTREAM) | ||
262 | return hpi_outstream_group_add(hS, h_master, h_stream); | ||
263 | else | ||
264 | return hpi_instream_group_add(hS, h_master, h_stream); | ||
265 | } | ||
266 | |||
267 | static inline u16 hpi_stream_group_reset(struct hpi_hsubsys *hS, | ||
268 | u32 h_stream) | ||
269 | { | ||
270 | if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) | ||
271 | return hpi_outstream_group_reset(hS, h_stream); | ||
272 | else | ||
273 | return hpi_instream_group_reset(hS, h_stream); | ||
274 | } | ||
275 | |||
276 | static inline u16 hpi_stream_group_get_map(struct hpi_hsubsys *hS, | ||
277 | u32 h_stream, u32 *mo, u32 *mi) | ||
278 | { | ||
279 | if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) | ||
280 | return hpi_outstream_group_get_map(hS, h_stream, mo, mi); | ||
281 | else | ||
282 | return hpi_instream_group_get_map(hS, h_stream, mo, mi); | ||
283 | } | ||
284 | |||
285 | static u16 handle_error(u16 err, int line, char *filename) | ||
286 | { | ||
287 | if (err) | ||
288 | printk(KERN_WARNING | ||
289 | "in file %s, line %d: HPI error %d\n", | ||
290 | filename, line, err); | ||
291 | return err; | ||
292 | } | ||
293 | |||
294 | #define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__) | ||
295 | |||
296 | /***************************** GENERAL PCM ****************/ | ||
297 | #if REALLY_VERBOSE_LOGGING | ||
298 | static void print_hwparams(struct snd_pcm_hw_params *p) | ||
299 | { | ||
300 | snd_printd("HWPARAMS \n"); | ||
301 | snd_printd("samplerate %d \n", params_rate(p)); | ||
302 | snd_printd("channels %d \n", params_channels(p)); | ||
303 | snd_printd("format %d \n", params_format(p)); | ||
304 | snd_printd("subformat %d \n", params_subformat(p)); | ||
305 | snd_printd("buffer bytes %d \n", params_buffer_bytes(p)); | ||
306 | snd_printd("period bytes %d \n", params_period_bytes(p)); | ||
307 | snd_printd("access %d \n", params_access(p)); | ||
308 | snd_printd("period_size %d \n", params_period_size(p)); | ||
309 | snd_printd("periods %d \n", params_periods(p)); | ||
310 | snd_printd("buffer_size %d \n", params_buffer_size(p)); | ||
311 | } | ||
312 | #else | ||
313 | #define print_hwparams(x) | ||
314 | #endif | ||
315 | |||
316 | static snd_pcm_format_t hpi_to_alsa_formats[] = { | ||
317 | -1, /* INVALID */ | ||
318 | SNDRV_PCM_FORMAT_U8, /* HPI_FORMAT_PCM8_UNSIGNED 1 */ | ||
319 | SNDRV_PCM_FORMAT_S16, /* HPI_FORMAT_PCM16_SIGNED 2 */ | ||
320 | -1, /* HPI_FORMAT_MPEG_L1 3 */ | ||
321 | SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L2 4 */ | ||
322 | SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L3 5 */ | ||
323 | -1, /* HPI_FORMAT_DOLBY_AC2 6 */ | ||
324 | -1, /* HPI_FORMAT_DOLBY_AC3 7 */ | ||
325 | SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN 8 */ | ||
326 | -1, /* HPI_FORMAT_AA_TAGIT1_HITS 9 */ | ||
327 | -1, /* HPI_FORMAT_AA_TAGIT1_INSERTS 10 */ | ||
328 | SNDRV_PCM_FORMAT_S32, /* HPI_FORMAT_PCM32_SIGNED 11 */ | ||
329 | -1, /* HPI_FORMAT_RAW_BITSTREAM 12 */ | ||
330 | -1, /* HPI_FORMAT_AA_TAGIT1_HITS_EX1 13 */ | ||
331 | SNDRV_PCM_FORMAT_FLOAT, /* HPI_FORMAT_PCM32_FLOAT 14 */ | ||
332 | #if 1 | ||
333 | /* ALSA can't handle 3 byte sample size together with power-of-2 | ||
334 | * constraint on buffer_bytes, so disable this format | ||
335 | */ | ||
336 | -1 | ||
337 | #else | ||
338 | /* SNDRV_PCM_FORMAT_S24_3LE */ /* { HPI_FORMAT_PCM24_SIGNED 15 */ | ||
339 | #endif | ||
340 | }; | ||
341 | |||
342 | |||
343 | static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format, | ||
344 | u16 *hpi_format) | ||
345 | { | ||
346 | u16 format; | ||
347 | |||
348 | for (format = HPI_FORMAT_PCM8_UNSIGNED; | ||
349 | format <= HPI_FORMAT_PCM24_SIGNED; format++) { | ||
350 | if (hpi_to_alsa_formats[format] == alsa_format) { | ||
351 | *hpi_format = format; | ||
352 | return 0; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | snd_printd(KERN_WARNING "failed match for alsa format %d\n", | ||
357 | alsa_format); | ||
358 | *hpi_format = 0; | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | |||
362 | static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi, | ||
363 | struct snd_pcm_hardware *pcmhw) | ||
364 | { | ||
365 | u16 err; | ||
366 | u32 h_control; | ||
367 | u32 sample_rate; | ||
368 | int idx; | ||
369 | unsigned int rate_min = 200000; | ||
370 | unsigned int rate_max = 0; | ||
371 | unsigned int rates = 0; | ||
372 | |||
373 | if (asihpi->support_mrx) { | ||
374 | rates |= SNDRV_PCM_RATE_CONTINUOUS; | ||
375 | rates |= SNDRV_PCM_RATE_8000_96000; | ||
376 | rate_min = 8000; | ||
377 | rate_max = 100000; | ||
378 | } else { | ||
379 | /* on cards without SRC, | ||
380 | valid rates are determined by sampleclock */ | ||
381 | err = hpi_mixer_get_control(ss, asihpi->h_mixer, | ||
382 | HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, | ||
383 | HPI_CONTROL_SAMPLECLOCK, &h_control); | ||
384 | if (err) { | ||
385 | snd_printk(KERN_ERR | ||
386 | "no local sampleclock, err %d\n", err); | ||
387 | } | ||
388 | |||
389 | for (idx = 0; idx < 100; idx++) { | ||
390 | if (hpi_sample_clock_query_local_rate(ss, | ||
391 | h_control, idx, &sample_rate)) { | ||
392 | if (!idx) | ||
393 | snd_printk(KERN_ERR | ||
394 | "local rate query failed\n"); | ||
395 | |||
396 | break; | ||
397 | } | ||
398 | |||
399 | rate_min = min(rate_min, sample_rate); | ||
400 | rate_max = max(rate_max, sample_rate); | ||
401 | |||
402 | switch (sample_rate) { | ||
403 | case 5512: | ||
404 | rates |= SNDRV_PCM_RATE_5512; | ||
405 | break; | ||
406 | case 8000: | ||
407 | rates |= SNDRV_PCM_RATE_8000; | ||
408 | break; | ||
409 | case 11025: | ||
410 | rates |= SNDRV_PCM_RATE_11025; | ||
411 | break; | ||
412 | case 16000: | ||
413 | rates |= SNDRV_PCM_RATE_16000; | ||
414 | break; | ||
415 | case 22050: | ||
416 | rates |= SNDRV_PCM_RATE_22050; | ||
417 | break; | ||
418 | case 32000: | ||
419 | rates |= SNDRV_PCM_RATE_32000; | ||
420 | break; | ||
421 | case 44100: | ||
422 | rates |= SNDRV_PCM_RATE_44100; | ||
423 | break; | ||
424 | case 48000: | ||
425 | rates |= SNDRV_PCM_RATE_48000; | ||
426 | break; | ||
427 | case 64000: | ||
428 | rates |= SNDRV_PCM_RATE_64000; | ||
429 | break; | ||
430 | case 88200: | ||
431 | rates |= SNDRV_PCM_RATE_88200; | ||
432 | break; | ||
433 | case 96000: | ||
434 | rates |= SNDRV_PCM_RATE_96000; | ||
435 | break; | ||
436 | case 176400: | ||
437 | rates |= SNDRV_PCM_RATE_176400; | ||
438 | break; | ||
439 | case 192000: | ||
440 | rates |= SNDRV_PCM_RATE_192000; | ||
441 | break; | ||
442 | default: /* some other rate */ | ||
443 | rates |= SNDRV_PCM_RATE_KNOT; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | |||
448 | /* printk(KERN_INFO "Supported rates %X %d %d\n", | ||
449 | rates, rate_min, rate_max); */ | ||
450 | pcmhw->rates = rates; | ||
451 | pcmhw->rate_min = rate_min; | ||
452 | pcmhw->rate_max = rate_max; | ||
453 | } | ||
454 | |||
455 | static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, | ||
456 | struct snd_pcm_hw_params *params) | ||
457 | { | ||
458 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
459 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
460 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); | ||
461 | int err; | ||
462 | u16 format; | ||
463 | unsigned int bytes_per_sec; | ||
464 | |||
465 | print_hwparams(params); | ||
466 | err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
467 | if (err < 0) | ||
468 | return err; | ||
469 | err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format); | ||
470 | if (err) | ||
471 | return err; | ||
472 | |||
473 | VPRINTK1(KERN_INFO "format %d, %d chans, %d_hz\n", | ||
474 | format, params_channels(params), | ||
475 | params_rate(params)); | ||
476 | |||
477 | hpi_handle_error(hpi_format_create(&dpcm->format, | ||
478 | params_channels(params), | ||
479 | format, params_rate(params), 0, 0)); | ||
480 | |||
481 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
482 | if (hpi_instream_reset(ss, dpcm->h_stream) != 0) | ||
483 | return -EINVAL; | ||
484 | |||
485 | if (hpi_instream_set_format(ss, | ||
486 | dpcm->h_stream, &dpcm->format) != 0) | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | |||
490 | dpcm->hpi_buffer_attached = 0; | ||
491 | if (card->support_mmap) { | ||
492 | |||
493 | err = hpi_stream_host_buffer_attach(ss, dpcm->h_stream, | ||
494 | params_buffer_bytes(params), runtime->dma_addr); | ||
495 | if (err == 0) { | ||
496 | snd_printd(KERN_INFO | ||
497 | "stream_host_buffer_attach succeeded %u %lu\n", | ||
498 | params_buffer_bytes(params), | ||
499 | (unsigned long)runtime->dma_addr); | ||
500 | } else { | ||
501 | snd_printd(KERN_INFO | ||
502 | "stream_host_buffer_attach error %d\n", | ||
503 | err); | ||
504 | return -ENOMEM; | ||
505 | } | ||
506 | |||
507 | err = hpi_stream_get_info_ex(ss, dpcm->h_stream, NULL, | ||
508 | &dpcm->hpi_buffer_attached, | ||
509 | NULL, NULL, NULL); | ||
510 | |||
511 | snd_printd(KERN_INFO "stream_host_buffer_attach status 0x%x\n", | ||
512 | dpcm->hpi_buffer_attached); | ||
513 | } | ||
514 | bytes_per_sec = params_rate(params) * params_channels(params); | ||
515 | bytes_per_sec *= snd_pcm_format_width(params_format(params)); | ||
516 | bytes_per_sec /= 8; | ||
517 | if (bytes_per_sec <= 0) | ||
518 | return -EINVAL; | ||
519 | |||
520 | dpcm->bytes_per_sec = bytes_per_sec; | ||
521 | dpcm->pcm_size = params_buffer_bytes(params); | ||
522 | dpcm->pcm_count = params_period_bytes(params); | ||
523 | snd_printd(KERN_INFO "pcm_size=%d, pcm_count=%d, bps=%d\n", | ||
524 | dpcm->pcm_size, dpcm->pcm_count, bytes_per_sec); | ||
525 | |||
526 | dpcm->pcm_irq_pos = 0; | ||
527 | dpcm->pcm_buf_pos = 0; | ||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream * | ||
532 | substream) | ||
533 | { | ||
534 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
535 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
536 | int expiry; | ||
537 | |||
538 | expiry = (dpcm->pcm_count * HZ / dpcm->bytes_per_sec); | ||
539 | /* wait longer the first time, for samples to propagate */ | ||
540 | expiry = max(expiry, 20); | ||
541 | dpcm->timer.expires = jiffies + expiry; | ||
542 | dpcm->respawn_timer = 1; | ||
543 | add_timer(&dpcm->timer); | ||
544 | } | ||
545 | |||
546 | static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream) | ||
547 | { | ||
548 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
549 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
550 | |||
551 | dpcm->respawn_timer = 0; | ||
552 | del_timer(&dpcm->timer); | ||
553 | } | ||
554 | |||
555 | static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | ||
556 | int cmd) | ||
557 | { | ||
558 | struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data; | ||
559 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); | ||
560 | struct snd_pcm_substream *s; | ||
561 | u16 e; | ||
562 | |||
563 | snd_printd("trigger %dstream %d\n", | ||
564 | substream->stream, substream->number); | ||
565 | switch (cmd) { | ||
566 | case SNDRV_PCM_TRIGGER_START: | ||
567 | snd_pcm_group_for_each_entry(s, substream) { | ||
568 | struct snd_card_asihpi_pcm *ds; | ||
569 | ds = s->runtime->private_data; | ||
570 | |||
571 | if (snd_pcm_substream_chip(s) != card) | ||
572 | continue; | ||
573 | |||
574 | if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) && | ||
575 | (card->support_mmap)) { | ||
576 | /* How do I know how much valid data is present | ||
577 | * in buffer? Just guessing 2 periods, but if | ||
578 | * buffer is bigger it may contain even more | ||
579 | * data?? | ||
580 | */ | ||
581 | unsigned int preload = ds->pcm_count * 2; | ||
582 | VPRINTK2("preload %d\n", preload); | ||
583 | hpi_handle_error(hpi_outstream_write_buf( | ||
584 | ss, ds->h_stream, | ||
585 | &s->runtime->dma_area[0], | ||
586 | preload, | ||
587 | &ds->format)); | ||
588 | } | ||
589 | |||
590 | if (card->support_grouping) { | ||
591 | VPRINTK1("\t_group %dstream %d\n", s->stream, | ||
592 | s->number); | ||
593 | e = hpi_stream_group_add(ss, | ||
594 | dpcm->h_stream, | ||
595 | ds->h_stream); | ||
596 | if (!e) { | ||
597 | snd_pcm_trigger_done(s, substream); | ||
598 | } else { | ||
599 | hpi_handle_error(e); | ||
600 | break; | ||
601 | } | ||
602 | } else | ||
603 | break; | ||
604 | } | ||
605 | snd_printd("start\n"); | ||
606 | /* start the master stream */ | ||
607 | snd_card_asihpi_pcm_timer_start(substream); | ||
608 | hpi_handle_error(hpi_stream_start(ss, dpcm->h_stream)); | ||
609 | break; | ||
610 | |||
611 | case SNDRV_PCM_TRIGGER_STOP: | ||
612 | snd_card_asihpi_pcm_timer_stop(substream); | ||
613 | snd_pcm_group_for_each_entry(s, substream) { | ||
614 | if (snd_pcm_substream_chip(s) != card) | ||
615 | continue; | ||
616 | |||
617 | /*? workaround linked streams don't | ||
618 | transition to SETUP 20070706*/ | ||
619 | s->runtime->status->state = SNDRV_PCM_STATE_SETUP; | ||
620 | |||
621 | if (card->support_grouping) { | ||
622 | VPRINTK1("\t_group %dstream %d\n", s->stream, | ||
623 | s->number); | ||
624 | snd_pcm_trigger_done(s, substream); | ||
625 | } else | ||
626 | break; | ||
627 | } | ||
628 | snd_printd("stop\n"); | ||
629 | |||
630 | /* _prepare and _hwparams reset the stream */ | ||
631 | hpi_handle_error(hpi_stream_stop(ss, dpcm->h_stream)); | ||
632 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
633 | hpi_handle_error( | ||
634 | hpi_outstream_reset(ss, dpcm->h_stream)); | ||
635 | |||
636 | if (card->support_grouping) | ||
637 | hpi_handle_error(hpi_stream_group_reset(ss, | ||
638 | dpcm->h_stream)); | ||
639 | break; | ||
640 | |||
641 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
642 | snd_printd("pause release\n"); | ||
643 | hpi_handle_error(hpi_stream_start(ss, dpcm->h_stream)); | ||
644 | snd_card_asihpi_pcm_timer_start(substream); | ||
645 | break; | ||
646 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
647 | snd_printd("pause\n"); | ||
648 | snd_card_asihpi_pcm_timer_stop(substream); | ||
649 | hpi_handle_error(hpi_stream_stop(ss, dpcm->h_stream)); | ||
650 | break; | ||
651 | default: | ||
652 | snd_printd("\tINVALID\n"); | ||
653 | return -EINVAL; | ||
654 | } | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | static int | ||
660 | snd_card_asihpi_hw_free(struct snd_pcm_substream *substream) | ||
661 | { | ||
662 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
663 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
664 | if (dpcm->hpi_buffer_attached) | ||
665 | hpi_stream_host_buffer_detach(ss, dpcm->h_stream); | ||
666 | |||
667 | snd_pcm_lib_free_pages(substream); | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime) | ||
672 | { | ||
673 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
674 | kfree(dpcm); | ||
675 | } | ||
676 | |||
677 | /*algorithm outline | ||
678 | Without linking degenerates to getting single stream pos etc | ||
679 | Without mmap 2nd loop degenerates to snd_pcm_period_elapsed | ||
680 | */ | ||
681 | /* | ||
682 | buf_pos=get_buf_pos(s); | ||
683 | for_each_linked_stream(s) { | ||
684 | buf_pos=get_buf_pos(s); | ||
685 | min_buf_pos = modulo_min(min_buf_pos, buf_pos, pcm_size) | ||
686 | new_data = min(new_data, calc_new_data(buf_pos,irq_pos) | ||
687 | } | ||
688 | timer.expires = jiffies + predict_next_period_ready(min_buf_pos); | ||
689 | for_each_linked_stream(s) { | ||
690 | s->buf_pos = min_buf_pos; | ||
691 | if (new_data > pcm_count) { | ||
692 | if (mmap) { | ||
693 | irq_pos = (irq_pos + pcm_count) % pcm_size; | ||
694 | if (playback) { | ||
695 | write(pcm_count); | ||
696 | } else { | ||
697 | read(pcm_count); | ||
698 | } | ||
699 | } | ||
700 | snd_pcm_period_elapsed(s); | ||
701 | } | ||
702 | } | ||
703 | */ | ||
704 | |||
705 | /** Minimum of 2 modulo values. Works correctly when the difference between | ||
706 | * the values is less than half the modulus | ||
707 | */ | ||
708 | static inline unsigned int modulo_min(unsigned int a, unsigned int b, | ||
709 | unsigned long int modulus) | ||
710 | { | ||
711 | unsigned int result; | ||
712 | if (((a-b) % modulus) < (modulus/2)) | ||
713 | result = b; | ||
714 | else | ||
715 | result = a; | ||
716 | |||
717 | return result; | ||
718 | } | ||
719 | |||
720 | /** Timer function, equivalent to interrupt service routine for cards | ||
721 | */ | ||
722 | static void snd_card_asihpi_timer_function(unsigned long data) | ||
723 | { | ||
724 | struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data; | ||
725 | struct snd_card_asihpi *card = snd_pcm_substream_chip(dpcm->substream); | ||
726 | struct snd_pcm_runtime *runtime; | ||
727 | struct snd_pcm_substream *s; | ||
728 | unsigned int newdata = 0; | ||
729 | unsigned int buf_pos, min_buf_pos = 0; | ||
730 | unsigned int remdata, xfercount, next_jiffies; | ||
731 | int first = 1; | ||
732 | u16 state; | ||
733 | u32 buffer_size, data_avail, samples_played, aux; | ||
734 | |||
735 | /* find minimum newdata and buffer pos in group */ | ||
736 | snd_pcm_group_for_each_entry(s, dpcm->substream) { | ||
737 | struct snd_card_asihpi_pcm *ds = s->runtime->private_data; | ||
738 | runtime = s->runtime; | ||
739 | |||
740 | if (snd_pcm_substream_chip(s) != card) | ||
741 | continue; | ||
742 | |||
743 | hpi_handle_error(hpi_stream_get_info_ex(ss, | ||
744 | ds->h_stream, &state, | ||
745 | &buffer_size, &data_avail, | ||
746 | &samples_played, &aux)); | ||
747 | |||
748 | /* number of bytes in on-card buffer */ | ||
749 | runtime->delay = aux; | ||
750 | |||
751 | if (state == HPI_STATE_DRAINED) { | ||
752 | snd_printd(KERN_WARNING "outstream %d drained\n", | ||
753 | s->number); | ||
754 | snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); | ||
755 | return; | ||
756 | } | ||
757 | |||
758 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
759 | buf_pos = frames_to_bytes(runtime, samples_played); | ||
760 | } else { | ||
761 | buf_pos = data_avail + ds->pcm_irq_pos; | ||
762 | } | ||
763 | |||
764 | if (first) { | ||
765 | /* can't statically init min when wrap is involved */ | ||
766 | min_buf_pos = buf_pos; | ||
767 | newdata = (buf_pos - ds->pcm_irq_pos) % ds->pcm_size; | ||
768 | first = 0; | ||
769 | } else { | ||
770 | min_buf_pos = | ||
771 | modulo_min(min_buf_pos, buf_pos, UINT_MAX+1L); | ||
772 | newdata = min( | ||
773 | (buf_pos - ds->pcm_irq_pos) % ds->pcm_size, | ||
774 | newdata); | ||
775 | } | ||
776 | |||
777 | VPRINTK1("PB timer hw_ptr x%04lX, appl_ptr x%04lX\n", | ||
778 | (unsigned long)frames_to_bytes(runtime, | ||
779 | runtime->status->hw_ptr), | ||
780 | (unsigned long)frames_to_bytes(runtime, | ||
781 | runtime->control->appl_ptr)); | ||
782 | VPRINTK1("%d S=%d, irq=%04X, pos=x%04X, left=x%04X," | ||
783 | " aux=x%04X space=x%04X\n", s->number, | ||
784 | state, ds->pcm_irq_pos, buf_pos, (int)data_avail, | ||
785 | (int)aux, buffer_size-data_avail); | ||
786 | } | ||
787 | |||
788 | remdata = newdata % dpcm->pcm_count; | ||
789 | xfercount = newdata - remdata; /* a multiple of pcm_count */ | ||
790 | next_jiffies = ((dpcm->pcm_count-remdata) * HZ / dpcm->bytes_per_sec)+1; | ||
791 | next_jiffies = max(next_jiffies, 2U * HZ / 1000U); | ||
792 | dpcm->timer.expires = jiffies + next_jiffies; | ||
793 | VPRINTK1("jif %d buf pos x%04X newdata x%04X xc x%04X\n", | ||
794 | next_jiffies, min_buf_pos, newdata, xfercount); | ||
795 | |||
796 | snd_pcm_group_for_each_entry(s, dpcm->substream) { | ||
797 | struct snd_card_asihpi_pcm *ds = s->runtime->private_data; | ||
798 | ds->pcm_buf_pos = min_buf_pos; | ||
799 | |||
800 | if (xfercount) { | ||
801 | if (card->support_mmap) { | ||
802 | ds->pcm_irq_pos = ds->pcm_irq_pos + xfercount; | ||
803 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
804 | VPRINTK2("write OS%d x%04x\n", | ||
805 | s->number, | ||
806 | ds->pcm_count); | ||
807 | hpi_handle_error( | ||
808 | hpi_outstream_write_buf( | ||
809 | ss, ds->h_stream, | ||
810 | &s->runtime-> | ||
811 | dma_area[0], | ||
812 | xfercount, | ||
813 | &ds->format)); | ||
814 | } else { | ||
815 | VPRINTK2("read IS%d x%04x\n", | ||
816 | s->number, | ||
817 | dpcm->pcm_count); | ||
818 | hpi_handle_error( | ||
819 | hpi_instream_read_buf( | ||
820 | ss, ds->h_stream, | ||
821 | NULL, xfercount)); | ||
822 | } | ||
823 | } /* else R/W will be handled by read/write callbacks */ | ||
824 | snd_pcm_period_elapsed(s); | ||
825 | } | ||
826 | } | ||
827 | |||
828 | if (dpcm->respawn_timer) | ||
829 | add_timer(&dpcm->timer); | ||
830 | } | ||
831 | |||
832 | /***************************** PLAYBACK OPS ****************/ | ||
833 | static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, | ||
834 | unsigned int cmd, void *arg) | ||
835 | { | ||
836 | /* snd_printd(KERN_INFO "Playback ioctl %d\n", cmd); */ | ||
837 | return snd_pcm_lib_ioctl(substream, cmd, arg); | ||
838 | } | ||
839 | |||
840 | static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream * | ||
841 | substream) | ||
842 | { | ||
843 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
844 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
845 | |||
846 | snd_printd(KERN_INFO "playback prepare %d\n", substream->number); | ||
847 | |||
848 | hpi_handle_error(hpi_outstream_reset(ss, dpcm->h_stream)); | ||
849 | dpcm->pcm_irq_pos = 0; | ||
850 | dpcm->pcm_buf_pos = 0; | ||
851 | |||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | static snd_pcm_uframes_t | ||
856 | snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream) | ||
857 | { | ||
858 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
859 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
860 | snd_pcm_uframes_t ptr; | ||
861 | |||
862 | u32 samples_played; | ||
863 | u16 err; | ||
864 | |||
865 | if (!snd_pcm_stream_linked(substream)) { | ||
866 | /* NOTE, can use samples played for playback position here and | ||
867 | * in timer fn because it LAGS the actual read pointer, and is a | ||
868 | * better representation of actual playout position | ||
869 | */ | ||
870 | err = hpi_outstream_get_info_ex(ss, dpcm->h_stream, NULL, | ||
871 | NULL, NULL, | ||
872 | &samples_played, NULL); | ||
873 | hpi_handle_error(err); | ||
874 | |||
875 | dpcm->pcm_buf_pos = frames_to_bytes(runtime, samples_played); | ||
876 | } | ||
877 | /* else must return most conservative value found in timer func | ||
878 | * by looping over all streams | ||
879 | */ | ||
880 | |||
881 | ptr = bytes_to_frames(runtime, dpcm->pcm_buf_pos % dpcm->pcm_size); | ||
882 | VPRINTK2("playback_pointer=%04ld\n", (unsigned long)ptr); | ||
883 | return ptr; | ||
884 | } | ||
885 | |||
886 | static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi, | ||
887 | u32 h_stream, | ||
888 | struct snd_pcm_hardware *pcmhw) | ||
889 | { | ||
890 | struct hpi_format hpi_format; | ||
891 | u16 format; | ||
892 | u16 err; | ||
893 | u32 h_control; | ||
894 | u32 sample_rate = 48000; | ||
895 | |||
896 | /* on cards without SRC, must query at valid rate, | ||
897 | * maybe set by external sync | ||
898 | */ | ||
899 | err = hpi_mixer_get_control(ss, asihpi->h_mixer, | ||
900 | HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, | ||
901 | HPI_CONTROL_SAMPLECLOCK, &h_control); | ||
902 | |||
903 | if (!err) | ||
904 | err = hpi_sample_clock_get_sample_rate(ss, h_control, | ||
905 | &sample_rate); | ||
906 | |||
907 | for (format = HPI_FORMAT_PCM8_UNSIGNED; | ||
908 | format <= HPI_FORMAT_PCM24_SIGNED; format++) { | ||
909 | err = hpi_format_create(&hpi_format, | ||
910 | 2, format, sample_rate, 128000, 0); | ||
911 | if (!err) | ||
912 | err = hpi_outstream_query_format(ss, h_stream, | ||
913 | &hpi_format); | ||
914 | if (!err && (hpi_to_alsa_formats[format] != -1)) | ||
915 | pcmhw->formats |= | ||
916 | (1ULL << hpi_to_alsa_formats[format]); | ||
917 | } | ||
918 | } | ||
919 | |||
920 | static struct snd_pcm_hardware snd_card_asihpi_playback = { | ||
921 | .channels_min = 1, | ||
922 | .channels_max = 2, | ||
923 | .buffer_bytes_max = BUFFER_BYTES_MAX, | ||
924 | .period_bytes_min = PERIOD_BYTES_MIN, | ||
925 | .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN, | ||
926 | .periods_min = PERIODS_MIN, | ||
927 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | ||
928 | .fifo_size = 0, | ||
929 | }; | ||
930 | |||
931 | static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) | ||
932 | { | ||
933 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
934 | struct snd_card_asihpi_pcm *dpcm; | ||
935 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); | ||
936 | int err; | ||
937 | |||
938 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); | ||
939 | if (dpcm == NULL) | ||
940 | return -ENOMEM; | ||
941 | |||
942 | err = | ||
943 | hpi_outstream_open(ss, card->adapter_index, | ||
944 | substream->number, &dpcm->h_stream); | ||
945 | hpi_handle_error(err); | ||
946 | if (err) | ||
947 | kfree(dpcm); | ||
948 | if (err == HPI_ERROR_OBJ_ALREADY_OPEN) | ||
949 | return -EBUSY; | ||
950 | if (err) | ||
951 | return -EIO; | ||
952 | |||
953 | /*? also check ASI5000 samplerate source | ||
954 | If external, only support external rate. | ||
955 | If internal and other stream playing, cant switch | ||
956 | */ | ||
957 | |||
958 | init_timer(&dpcm->timer); | ||
959 | dpcm->timer.data = (unsigned long) dpcm; | ||
960 | dpcm->timer.function = snd_card_asihpi_timer_function; | ||
961 | dpcm->substream = substream; | ||
962 | runtime->private_data = dpcm; | ||
963 | runtime->private_free = snd_card_asihpi_runtime_free; | ||
964 | |||
965 | snd_card_asihpi_playback.channels_max = card->out_max_chans; | ||
966 | /*?snd_card_asihpi_playback.period_bytes_min = | ||
967 | card->out_max_chans * 4096; */ | ||
968 | |||
969 | snd_card_asihpi_playback_format(card, dpcm->h_stream, | ||
970 | &snd_card_asihpi_playback); | ||
971 | |||
972 | snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_playback); | ||
973 | |||
974 | snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED | | ||
975 | SNDRV_PCM_INFO_DOUBLE | | ||
976 | SNDRV_PCM_INFO_BATCH | | ||
977 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
978 | SNDRV_PCM_INFO_PAUSE; | ||
979 | |||
980 | if (card->support_mmap) | ||
981 | snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP | | ||
982 | SNDRV_PCM_INFO_MMAP_VALID; | ||
983 | |||
984 | if (card->support_grouping) | ||
985 | snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START; | ||
986 | |||
987 | /* struct is copied, so can create initializer dynamically */ | ||
988 | runtime->hw = snd_card_asihpi_playback; | ||
989 | |||
990 | if (card->support_mmap) | ||
991 | err = snd_pcm_hw_constraint_pow2(runtime, 0, | ||
992 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES); | ||
993 | if (err < 0) | ||
994 | return err; | ||
995 | |||
996 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
997 | card->update_interval_frames); | ||
998 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
999 | card->update_interval_frames * 4, UINT_MAX); | ||
1000 | |||
1001 | snd_pcm_set_sync(substream); | ||
1002 | |||
1003 | snd_printd(KERN_INFO "playback open\n"); | ||
1004 | |||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream) | ||
1009 | { | ||
1010 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1011 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
1012 | |||
1013 | hpi_handle_error(hpi_outstream_close(ss, dpcm->h_stream)); | ||
1014 | snd_printd(KERN_INFO "playback close\n"); | ||
1015 | |||
1016 | return 0; | ||
1017 | } | ||
1018 | |||
1019 | static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream, | ||
1020 | int channel, | ||
1021 | snd_pcm_uframes_t pos, | ||
1022 | void __user *src, | ||
1023 | snd_pcm_uframes_t count) | ||
1024 | { | ||
1025 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1026 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
1027 | unsigned int len; | ||
1028 | |||
1029 | len = frames_to_bytes(runtime, count); | ||
1030 | |||
1031 | if (copy_from_user(runtime->dma_area, src, len)) | ||
1032 | return -EFAULT; | ||
1033 | |||
1034 | VPRINTK2(KERN_DEBUG "playback copy%d %u bytes\n", | ||
1035 | substream->number, len); | ||
1036 | |||
1037 | hpi_handle_error(hpi_outstream_write_buf(ss, dpcm->h_stream, | ||
1038 | runtime->dma_area, len, &dpcm->format)); | ||
1039 | |||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static int snd_card_asihpi_playback_silence(struct snd_pcm_substream * | ||
1044 | substream, int channel, | ||
1045 | snd_pcm_uframes_t pos, | ||
1046 | snd_pcm_uframes_t count) | ||
1047 | { | ||
1048 | unsigned int len; | ||
1049 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1050 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
1051 | |||
1052 | len = frames_to_bytes(runtime, count); | ||
1053 | snd_printd(KERN_INFO "playback silence %u bytes\n", len); | ||
1054 | |||
1055 | memset(runtime->dma_area, 0, len); | ||
1056 | hpi_handle_error(hpi_outstream_write_buf(ss, dpcm->h_stream, | ||
1057 | runtime->dma_area, len, &dpcm->format)); | ||
1058 | return 0; | ||
1059 | } | ||
1060 | |||
1061 | static struct snd_pcm_ops snd_card_asihpi_playback_ops = { | ||
1062 | .open = snd_card_asihpi_playback_open, | ||
1063 | .close = snd_card_asihpi_playback_close, | ||
1064 | .ioctl = snd_card_asihpi_playback_ioctl, | ||
1065 | .hw_params = snd_card_asihpi_pcm_hw_params, | ||
1066 | .hw_free = snd_card_asihpi_hw_free, | ||
1067 | .prepare = snd_card_asihpi_playback_prepare, | ||
1068 | .trigger = snd_card_asihpi_trigger, | ||
1069 | .pointer = snd_card_asihpi_playback_pointer, | ||
1070 | .copy = snd_card_asihpi_playback_copy, | ||
1071 | .silence = snd_card_asihpi_playback_silence, | ||
1072 | }; | ||
1073 | |||
1074 | static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = { | ||
1075 | .open = snd_card_asihpi_playback_open, | ||
1076 | .close = snd_card_asihpi_playback_close, | ||
1077 | .ioctl = snd_card_asihpi_playback_ioctl, | ||
1078 | .hw_params = snd_card_asihpi_pcm_hw_params, | ||
1079 | .hw_free = snd_card_asihpi_hw_free, | ||
1080 | .prepare = snd_card_asihpi_playback_prepare, | ||
1081 | .trigger = snd_card_asihpi_trigger, | ||
1082 | .pointer = snd_card_asihpi_playback_pointer, | ||
1083 | }; | ||
1084 | |||
1085 | /***************************** CAPTURE OPS ****************/ | ||
1086 | static snd_pcm_uframes_t | ||
1087 | snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream) | ||
1088 | { | ||
1089 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1090 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
1091 | |||
1092 | VPRINTK2("capture pointer %d=%d\n", | ||
1093 | substream->number, dpcm->pcm_buf_pos); | ||
1094 | /* NOTE Unlike playback can't use actual dwSamplesPlayed | ||
1095 | for the capture position, because those samples aren't yet in | ||
1096 | the local buffer available for reading. | ||
1097 | */ | ||
1098 | return bytes_to_frames(runtime, dpcm->pcm_buf_pos % dpcm->pcm_size); | ||
1099 | } | ||
1100 | |||
1101 | static int snd_card_asihpi_capture_ioctl(struct snd_pcm_substream *substream, | ||
1102 | unsigned int cmd, void *arg) | ||
1103 | { | ||
1104 | return snd_pcm_lib_ioctl(substream, cmd, arg); | ||
1105 | } | ||
1106 | |||
1107 | static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream) | ||
1108 | { | ||
1109 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1110 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
1111 | |||
1112 | hpi_handle_error(hpi_instream_reset(ss, dpcm->h_stream)); | ||
1113 | dpcm->pcm_irq_pos = 0; | ||
1114 | dpcm->pcm_buf_pos = 0; | ||
1115 | |||
1116 | snd_printd("capture prepare %d\n", substream->number); | ||
1117 | return 0; | ||
1118 | } | ||
1119 | |||
1120 | |||
1121 | |||
1122 | static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi, | ||
1123 | u32 h_stream, | ||
1124 | struct snd_pcm_hardware *pcmhw) | ||
1125 | { | ||
1126 | struct hpi_format hpi_format; | ||
1127 | u16 format; | ||
1128 | u16 err; | ||
1129 | u32 h_control; | ||
1130 | u32 sample_rate = 48000; | ||
1131 | |||
1132 | /* on cards without SRC, must query at valid rate, | ||
1133 | maybe set by external sync */ | ||
1134 | err = hpi_mixer_get_control(ss, asihpi->h_mixer, | ||
1135 | HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, | ||
1136 | HPI_CONTROL_SAMPLECLOCK, &h_control); | ||
1137 | |||
1138 | if (!err) | ||
1139 | err = hpi_sample_clock_get_sample_rate(ss, h_control, | ||
1140 | &sample_rate); | ||
1141 | |||
1142 | for (format = HPI_FORMAT_PCM8_UNSIGNED; | ||
1143 | format <= HPI_FORMAT_PCM24_SIGNED; format++) { | ||
1144 | |||
1145 | err = hpi_format_create(&hpi_format, 2, format, | ||
1146 | sample_rate, 128000, 0); | ||
1147 | if (!err) | ||
1148 | err = hpi_instream_query_format(ss, h_stream, | ||
1149 | &hpi_format); | ||
1150 | if (!err) | ||
1151 | pcmhw->formats |= | ||
1152 | (1ULL << hpi_to_alsa_formats[format]); | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1156 | |||
1157 | static struct snd_pcm_hardware snd_card_asihpi_capture = { | ||
1158 | .channels_min = 1, | ||
1159 | .channels_max = 2, | ||
1160 | .buffer_bytes_max = BUFFER_BYTES_MAX, | ||
1161 | .period_bytes_min = PERIOD_BYTES_MIN, | ||
1162 | .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN, | ||
1163 | .periods_min = PERIODS_MIN, | ||
1164 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | ||
1165 | .fifo_size = 0, | ||
1166 | }; | ||
1167 | |||
1168 | static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) | ||
1169 | { | ||
1170 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1171 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); | ||
1172 | struct snd_card_asihpi_pcm *dpcm; | ||
1173 | int err; | ||
1174 | |||
1175 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); | ||
1176 | if (dpcm == NULL) | ||
1177 | return -ENOMEM; | ||
1178 | |||
1179 | snd_printd("hpi_instream_open adapter %d stream %d\n", | ||
1180 | card->adapter_index, substream->number); | ||
1181 | |||
1182 | err = hpi_handle_error( | ||
1183 | hpi_instream_open(ss, card->adapter_index, | ||
1184 | substream->number, &dpcm->h_stream)); | ||
1185 | if (err) | ||
1186 | kfree(dpcm); | ||
1187 | if (err == HPI_ERROR_OBJ_ALREADY_OPEN) | ||
1188 | return -EBUSY; | ||
1189 | if (err) | ||
1190 | return -EIO; | ||
1191 | |||
1192 | |||
1193 | init_timer(&dpcm->timer); | ||
1194 | dpcm->timer.data = (unsigned long) dpcm; | ||
1195 | dpcm->timer.function = snd_card_asihpi_timer_function; | ||
1196 | dpcm->substream = substream; | ||
1197 | runtime->private_data = dpcm; | ||
1198 | runtime->private_free = snd_card_asihpi_runtime_free; | ||
1199 | |||
1200 | snd_card_asihpi_capture.channels_max = card->in_max_chans; | ||
1201 | snd_card_asihpi_capture_format(card, dpcm->h_stream, | ||
1202 | &snd_card_asihpi_capture); | ||
1203 | snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture); | ||
1204 | snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED; | ||
1205 | |||
1206 | if (card->support_mmap) | ||
1207 | snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP | | ||
1208 | SNDRV_PCM_INFO_MMAP_VALID; | ||
1209 | |||
1210 | runtime->hw = snd_card_asihpi_capture; | ||
1211 | |||
1212 | if (card->support_mmap) | ||
1213 | err = snd_pcm_hw_constraint_pow2(runtime, 0, | ||
1214 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES); | ||
1215 | if (err < 0) | ||
1216 | return err; | ||
1217 | |||
1218 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
1219 | card->update_interval_frames); | ||
1220 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
1221 | card->update_interval_frames * 2, UINT_MAX); | ||
1222 | |||
1223 | snd_pcm_set_sync(substream); | ||
1224 | |||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream) | ||
1229 | { | ||
1230 | struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data; | ||
1231 | |||
1232 | hpi_handle_error(hpi_instream_close(ss, dpcm->h_stream)); | ||
1233 | return 0; | ||
1234 | } | ||
1235 | |||
1236 | static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream, | ||
1237 | int channel, snd_pcm_uframes_t pos, | ||
1238 | void __user *dst, snd_pcm_uframes_t count) | ||
1239 | { | ||
1240 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1241 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | ||
1242 | u32 data_size; | ||
1243 | |||
1244 | data_size = frames_to_bytes(runtime, count); | ||
1245 | |||
1246 | VPRINTK2("capture copy%d %d bytes\n", substream->number, data_size); | ||
1247 | hpi_handle_error(hpi_instream_read_buf(ss, dpcm->h_stream, | ||
1248 | runtime->dma_area, data_size)); | ||
1249 | |||
1250 | /* Used by capture_pointer */ | ||
1251 | dpcm->pcm_irq_pos = dpcm->pcm_irq_pos + data_size; | ||
1252 | |||
1253 | if (copy_to_user(dst, runtime->dma_area, data_size)) | ||
1254 | return -EFAULT; | ||
1255 | |||
1256 | return 0; | ||
1257 | } | ||
1258 | |||
1259 | static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { | ||
1260 | .open = snd_card_asihpi_capture_open, | ||
1261 | .close = snd_card_asihpi_capture_close, | ||
1262 | .ioctl = snd_card_asihpi_capture_ioctl, | ||
1263 | .hw_params = snd_card_asihpi_pcm_hw_params, | ||
1264 | .hw_free = snd_card_asihpi_hw_free, | ||
1265 | .prepare = snd_card_asihpi_capture_prepare, | ||
1266 | .trigger = snd_card_asihpi_trigger, | ||
1267 | .pointer = snd_card_asihpi_capture_pointer, | ||
1268 | }; | ||
1269 | |||
1270 | static struct snd_pcm_ops snd_card_asihpi_capture_ops = { | ||
1271 | .open = snd_card_asihpi_capture_open, | ||
1272 | .close = snd_card_asihpi_capture_close, | ||
1273 | .ioctl = snd_card_asihpi_capture_ioctl, | ||
1274 | .hw_params = snd_card_asihpi_pcm_hw_params, | ||
1275 | .hw_free = snd_card_asihpi_hw_free, | ||
1276 | .prepare = snd_card_asihpi_capture_prepare, | ||
1277 | .trigger = snd_card_asihpi_trigger, | ||
1278 | .pointer = snd_card_asihpi_capture_pointer, | ||
1279 | .copy = snd_card_asihpi_capture_copy | ||
1280 | }; | ||
1281 | |||
1282 | static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, | ||
1283 | int device, int substreams) | ||
1284 | { | ||
1285 | struct snd_pcm *pcm; | ||
1286 | int err; | ||
1287 | |||
1288 | err = snd_pcm_new(asihpi->card, "asihpi PCM", device, | ||
1289 | asihpi->num_outstreams, asihpi->num_instreams, | ||
1290 | &pcm); | ||
1291 | if (err < 0) | ||
1292 | return err; | ||
1293 | /* pointer to ops struct is stored, dont change ops afterwards! */ | ||
1294 | if (asihpi->support_mmap) { | ||
1295 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
1296 | &snd_card_asihpi_playback_mmap_ops); | ||
1297 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
1298 | &snd_card_asihpi_capture_mmap_ops); | ||
1299 | } else { | ||
1300 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
1301 | &snd_card_asihpi_playback_ops); | ||
1302 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
1303 | &snd_card_asihpi_capture_ops); | ||
1304 | } | ||
1305 | |||
1306 | pcm->private_data = asihpi; | ||
1307 | pcm->info_flags = 0; | ||
1308 | strcpy(pcm->name, "asihpi PCM"); | ||
1309 | |||
1310 | /*? do we want to emulate MMAP for non-BBM cards? | ||
1311 | Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */ | ||
1312 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
1313 | snd_dma_pci_data(asihpi->pci), | ||
1314 | 64*1024, BUFFER_BYTES_MAX); | ||
1315 | |||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | /***************************** MIXER CONTROLS ****************/ | ||
1320 | struct hpi_control { | ||
1321 | u32 h_control; | ||
1322 | u16 control_type; | ||
1323 | u16 src_node_type; | ||
1324 | u16 src_node_index; | ||
1325 | u16 dst_node_type; | ||
1326 | u16 dst_node_index; | ||
1327 | u16 band; | ||
1328 | char name[44]; /* copied to snd_ctl_elem_id.name[44]; */ | ||
1329 | }; | ||
1330 | |||
1331 | static char *asihpi_tuner_band_names[] = | ||
1332 | { | ||
1333 | "invalid", | ||
1334 | "AM", | ||
1335 | "FM mono", | ||
1336 | "TV NTSC-M", | ||
1337 | "FM stereo", | ||
1338 | "AUX", | ||
1339 | "TV PAL BG", | ||
1340 | "TV PAL I", | ||
1341 | "TV PAL DK", | ||
1342 | "TV SECAM", | ||
1343 | }; | ||
1344 | |||
1345 | compile_time_assert( | ||
1346 | (ARRAY_SIZE(asihpi_tuner_band_names) == | ||
1347 | (HPI_TUNER_BAND_LAST+1)), | ||
1348 | assert_tuner_band_names_size); | ||
1349 | |||
1350 | #if ASI_STYLE_NAMES | ||
1351 | static char *asihpi_src_names[] = | ||
1352 | { | ||
1353 | "no source", | ||
1354 | "outstream", | ||
1355 | "line_in", | ||
1356 | "aes_in", | ||
1357 | "tuner", | ||
1358 | "RF", | ||
1359 | "clock", | ||
1360 | "bitstr", | ||
1361 | "mic", | ||
1362 | "cobranet", | ||
1363 | "analog_in", | ||
1364 | "adapter", | ||
1365 | }; | ||
1366 | #else | ||
1367 | static char *asihpi_src_names[] = | ||
1368 | { | ||
1369 | "no source", | ||
1370 | "PCM playback", | ||
1371 | "line in", | ||
1372 | "digital in", | ||
1373 | "tuner", | ||
1374 | "RF", | ||
1375 | "clock", | ||
1376 | "bitstream", | ||
1377 | "mic", | ||
1378 | "cobranet in", | ||
1379 | "analog in", | ||
1380 | "adapter", | ||
1381 | }; | ||
1382 | #endif | ||
1383 | |||
1384 | compile_time_assert( | ||
1385 | (ARRAY_SIZE(asihpi_src_names) == | ||
1386 | (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)), | ||
1387 | assert_src_names_size); | ||
1388 | |||
1389 | #if ASI_STYLE_NAMES | ||
1390 | static char *asihpi_dst_names[] = | ||
1391 | { | ||
1392 | "no destination", | ||
1393 | "instream", | ||
1394 | "line_out", | ||
1395 | "aes_out", | ||
1396 | "RF", | ||
1397 | "speaker" , | ||
1398 | "cobranet", | ||
1399 | "analog_out", | ||
1400 | }; | ||
1401 | #else | ||
1402 | static char *asihpi_dst_names[] = | ||
1403 | { | ||
1404 | "no destination", | ||
1405 | "PCM capture", | ||
1406 | "line out", | ||
1407 | "digital out", | ||
1408 | "RF", | ||
1409 | "speaker", | ||
1410 | "cobranet out", | ||
1411 | "analog out" | ||
1412 | }; | ||
1413 | #endif | ||
1414 | |||
1415 | compile_time_assert( | ||
1416 | (ARRAY_SIZE(asihpi_dst_names) == | ||
1417 | (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)), | ||
1418 | assert_dst_names_size); | ||
1419 | |||
1420 | static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl, | ||
1421 | struct snd_card_asihpi *asihpi) | ||
1422 | { | ||
1423 | int err; | ||
1424 | |||
1425 | err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi)); | ||
1426 | if (err < 0) | ||
1427 | return err; | ||
1428 | else if (mixer_dump) | ||
1429 | snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index); | ||
1430 | |||
1431 | return 0; | ||
1432 | } | ||
1433 | |||
1434 | /* Convert HPI control name and location into ALSA control name */ | ||
1435 | static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, | ||
1436 | struct hpi_control *hpi_ctl, | ||
1437 | char *name) | ||
1438 | { | ||
1439 | memset(snd_control, 0, sizeof(*snd_control)); | ||
1440 | snd_control->name = hpi_ctl->name; | ||
1441 | snd_control->private_value = hpi_ctl->h_control; | ||
1442 | snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1443 | snd_control->index = 0; | ||
1444 | |||
1445 | if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type) | ||
1446 | sprintf(hpi_ctl->name, "%s%d to %s%d %s", | ||
1447 | asihpi_src_names[hpi_ctl->src_node_type], | ||
1448 | hpi_ctl->src_node_index, | ||
1449 | asihpi_dst_names[hpi_ctl->dst_node_type], | ||
1450 | hpi_ctl->dst_node_index, | ||
1451 | name); | ||
1452 | else if (hpi_ctl->dst_node_type) { | ||
1453 | sprintf(hpi_ctl->name, "%s%d %s", | ||
1454 | asihpi_dst_names[hpi_ctl->dst_node_type], | ||
1455 | hpi_ctl->dst_node_index, | ||
1456 | name); | ||
1457 | } else { | ||
1458 | sprintf(hpi_ctl->name, "%s%d %s", | ||
1459 | asihpi_src_names[hpi_ctl->src_node_type], | ||
1460 | hpi_ctl->src_node_index, | ||
1461 | name); | ||
1462 | } | ||
1463 | } | ||
1464 | |||
1465 | /*------------------------------------------------------------ | ||
1466 | Volume controls | ||
1467 | ------------------------------------------------------------*/ | ||
1468 | #define VOL_STEP_mB 1 | ||
1469 | static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol, | ||
1470 | struct snd_ctl_elem_info *uinfo) | ||
1471 | { | ||
1472 | u32 h_control = kcontrol->private_value; | ||
1473 | u16 err; | ||
1474 | /* native gains are in millibels */ | ||
1475 | short min_gain_mB; | ||
1476 | short max_gain_mB; | ||
1477 | short step_gain_mB; | ||
1478 | |||
1479 | err = hpi_volume_query_range(ss, h_control, | ||
1480 | &min_gain_mB, &max_gain_mB, &step_gain_mB); | ||
1481 | if (err) { | ||
1482 | max_gain_mB = 0; | ||
1483 | min_gain_mB = -10000; | ||
1484 | step_gain_mB = VOL_STEP_mB; | ||
1485 | } | ||
1486 | |||
1487 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1488 | uinfo->count = 2; | ||
1489 | uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB; | ||
1490 | uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB; | ||
1491 | uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB; | ||
1492 | return 0; | ||
1493 | } | ||
1494 | |||
1495 | static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol, | ||
1496 | struct snd_ctl_elem_value *ucontrol) | ||
1497 | { | ||
1498 | u32 h_control = kcontrol->private_value; | ||
1499 | short an_gain_mB[HPI_MAX_CHANNELS]; | ||
1500 | |||
1501 | hpi_handle_error(hpi_volume_get_gain(ss, h_control, an_gain_mB)); | ||
1502 | ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB; | ||
1503 | ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB; | ||
1504 | |||
1505 | return 0; | ||
1506 | } | ||
1507 | |||
1508 | static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol, | ||
1509 | struct snd_ctl_elem_value *ucontrol) | ||
1510 | { | ||
1511 | int change; | ||
1512 | u32 h_control = kcontrol->private_value; | ||
1513 | short an_gain_mB[HPI_MAX_CHANNELS]; | ||
1514 | |||
1515 | an_gain_mB[0] = | ||
1516 | (ucontrol->value.integer.value[0]) * VOL_STEP_mB; | ||
1517 | an_gain_mB[1] = | ||
1518 | (ucontrol->value.integer.value[1]) * VOL_STEP_mB; | ||
1519 | /* change = asihpi->mixer_volume[addr][0] != left || | ||
1520 | asihpi->mixer_volume[addr][1] != right; | ||
1521 | */ | ||
1522 | change = 1; | ||
1523 | hpi_handle_error(hpi_volume_set_gain(ss, h_control, an_gain_mB)); | ||
1524 | return change; | ||
1525 | } | ||
1526 | |||
1527 | static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0); | ||
1528 | |||
1529 | static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, | ||
1530 | struct hpi_control *hpi_ctl) | ||
1531 | { | ||
1532 | struct snd_card *card = asihpi->card; | ||
1533 | struct snd_kcontrol_new snd_control; | ||
1534 | |||
1535 | asihpi_ctl_init(&snd_control, hpi_ctl, "volume"); | ||
1536 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1537 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
1538 | snd_control.info = snd_asihpi_volume_info; | ||
1539 | snd_control.get = snd_asihpi_volume_get; | ||
1540 | snd_control.put = snd_asihpi_volume_put; | ||
1541 | snd_control.tlv.p = db_scale_100; | ||
1542 | |||
1543 | return ctl_add(card, &snd_control, asihpi); | ||
1544 | } | ||
1545 | |||
1546 | /*------------------------------------------------------------ | ||
1547 | Level controls | ||
1548 | ------------------------------------------------------------*/ | ||
1549 | static int snd_asihpi_level_info(struct snd_kcontrol *kcontrol, | ||
1550 | struct snd_ctl_elem_info *uinfo) | ||
1551 | { | ||
1552 | u32 h_control = kcontrol->private_value; | ||
1553 | u16 err; | ||
1554 | short min_gain_mB; | ||
1555 | short max_gain_mB; | ||
1556 | short step_gain_mB; | ||
1557 | |||
1558 | err = | ||
1559 | hpi_level_query_range(ss, h_control, &min_gain_mB, | ||
1560 | &max_gain_mB, &step_gain_mB); | ||
1561 | if (err) { | ||
1562 | max_gain_mB = 2400; | ||
1563 | min_gain_mB = -1000; | ||
1564 | step_gain_mB = 100; | ||
1565 | } | ||
1566 | |||
1567 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1568 | uinfo->count = 2; | ||
1569 | uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB; | ||
1570 | uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB; | ||
1571 | uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB; | ||
1572 | return 0; | ||
1573 | } | ||
1574 | |||
1575 | static int snd_asihpi_level_get(struct snd_kcontrol *kcontrol, | ||
1576 | struct snd_ctl_elem_value *ucontrol) | ||
1577 | { | ||
1578 | u32 h_control = kcontrol->private_value; | ||
1579 | short an_gain_mB[HPI_MAX_CHANNELS]; | ||
1580 | |||
1581 | hpi_handle_error(hpi_level_get_gain(ss, h_control, an_gain_mB)); | ||
1582 | ucontrol->value.integer.value[0] = | ||
1583 | an_gain_mB[0] / HPI_UNITS_PER_dB; | ||
1584 | ucontrol->value.integer.value[1] = | ||
1585 | an_gain_mB[1] / HPI_UNITS_PER_dB; | ||
1586 | |||
1587 | return 0; | ||
1588 | } | ||
1589 | |||
1590 | static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol, | ||
1591 | struct snd_ctl_elem_value *ucontrol) | ||
1592 | { | ||
1593 | int change; | ||
1594 | u32 h_control = kcontrol->private_value; | ||
1595 | short an_gain_mB[HPI_MAX_CHANNELS]; | ||
1596 | |||
1597 | an_gain_mB[0] = | ||
1598 | (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB; | ||
1599 | an_gain_mB[1] = | ||
1600 | (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB; | ||
1601 | /* change = asihpi->mixer_level[addr][0] != left || | ||
1602 | asihpi->mixer_level[addr][1] != right; | ||
1603 | */ | ||
1604 | change = 1; | ||
1605 | hpi_handle_error(hpi_level_set_gain(ss, h_control, an_gain_mB)); | ||
1606 | return change; | ||
1607 | } | ||
1608 | |||
1609 | static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0); | ||
1610 | |||
1611 | static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi, | ||
1612 | struct hpi_control *hpi_ctl) | ||
1613 | { | ||
1614 | struct snd_card *card = asihpi->card; | ||
1615 | struct snd_kcontrol_new snd_control; | ||
1616 | |||
1617 | /* can't use 'volume' cos some nodes have volume as well */ | ||
1618 | asihpi_ctl_init(&snd_control, hpi_ctl, "level"); | ||
1619 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1620 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
1621 | snd_control.info = snd_asihpi_level_info; | ||
1622 | snd_control.get = snd_asihpi_level_get; | ||
1623 | snd_control.put = snd_asihpi_level_put; | ||
1624 | snd_control.tlv.p = db_scale_level; | ||
1625 | |||
1626 | return ctl_add(card, &snd_control, asihpi); | ||
1627 | } | ||
1628 | |||
1629 | /*------------------------------------------------------------ | ||
1630 | AESEBU controls | ||
1631 | ------------------------------------------------------------*/ | ||
1632 | |||
1633 | /* AESEBU format */ | ||
1634 | static char *asihpi_aesebu_format_names[] = | ||
1635 | { | ||
1636 | "N/A", | ||
1637 | "S/PDIF", | ||
1638 | "AES/EBU", | ||
1639 | }; | ||
1640 | |||
1641 | static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol, | ||
1642 | struct snd_ctl_elem_info *uinfo) | ||
1643 | { | ||
1644 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1645 | uinfo->count = 1; | ||
1646 | uinfo->value.enumerated.items = 3; | ||
1647 | |||
1648 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
1649 | uinfo->value.enumerated.item = | ||
1650 | uinfo->value.enumerated.items - 1; | ||
1651 | |||
1652 | strcpy(uinfo->value.enumerated.name, | ||
1653 | asihpi_aesebu_format_names[uinfo->value.enumerated.item]); | ||
1654 | |||
1655 | return 0; | ||
1656 | } | ||
1657 | |||
1658 | static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol, | ||
1659 | struct snd_ctl_elem_value *ucontrol, | ||
1660 | u16 (*func)(const struct hpi_hsubsys *, u32, u16 *)) | ||
1661 | { | ||
1662 | u32 h_control = kcontrol->private_value; | ||
1663 | u16 source, err; | ||
1664 | |||
1665 | err = func(ss, h_control, &source); | ||
1666 | |||
1667 | /* default to N/A */ | ||
1668 | ucontrol->value.enumerated.item[0] = 0; | ||
1669 | /* return success but set the control to N/A */ | ||
1670 | if (err) | ||
1671 | return 0; | ||
1672 | if (source == HPI_AESEBU_FORMAT_SPDIF) | ||
1673 | ucontrol->value.enumerated.item[0] = 1; | ||
1674 | if (source == HPI_AESEBU_FORMAT_AESEBU) | ||
1675 | ucontrol->value.enumerated.item[0] = 2; | ||
1676 | |||
1677 | return 0; | ||
1678 | } | ||
1679 | |||
1680 | static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol, | ||
1681 | struct snd_ctl_elem_value *ucontrol, | ||
1682 | u16 (*func)(const struct hpi_hsubsys *, u32, u16)) | ||
1683 | { | ||
1684 | u32 h_control = kcontrol->private_value; | ||
1685 | |||
1686 | /* default to S/PDIF */ | ||
1687 | u16 source = HPI_AESEBU_FORMAT_SPDIF; | ||
1688 | |||
1689 | if (ucontrol->value.enumerated.item[0] == 1) | ||
1690 | source = HPI_AESEBU_FORMAT_SPDIF; | ||
1691 | if (ucontrol->value.enumerated.item[0] == 2) | ||
1692 | source = HPI_AESEBU_FORMAT_AESEBU; | ||
1693 | |||
1694 | if (func(ss, h_control, source) != 0) | ||
1695 | return -EINVAL; | ||
1696 | |||
1697 | return 1; | ||
1698 | } | ||
1699 | |||
1700 | static int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol, | ||
1701 | struct snd_ctl_elem_value *ucontrol) { | ||
1702 | return snd_asihpi_aesebu_format_get(kcontrol, ucontrol, | ||
1703 | HPI_AESEBU__receiver_get_format); | ||
1704 | } | ||
1705 | |||
1706 | static int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol, | ||
1707 | struct snd_ctl_elem_value *ucontrol) { | ||
1708 | return snd_asihpi_aesebu_format_put(kcontrol, ucontrol, | ||
1709 | HPI_AESEBU__receiver_set_format); | ||
1710 | } | ||
1711 | |||
1712 | static int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol, | ||
1713 | struct snd_ctl_elem_info *uinfo) | ||
1714 | { | ||
1715 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1716 | uinfo->count = 1; | ||
1717 | |||
1718 | uinfo->value.integer.min = 0; | ||
1719 | uinfo->value.integer.max = 0X1F; | ||
1720 | uinfo->value.integer.step = 1; | ||
1721 | |||
1722 | return 0; | ||
1723 | } | ||
1724 | |||
1725 | static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol, | ||
1726 | struct snd_ctl_elem_value *ucontrol) { | ||
1727 | |||
1728 | u32 h_control = kcontrol->private_value; | ||
1729 | u16 status; | ||
1730 | |||
1731 | hpi_handle_error(HPI_AESEBU__receiver_get_error_status( | ||
1732 | ss, h_control, &status)); | ||
1733 | ucontrol->value.integer.value[0] = status; | ||
1734 | return 0; | ||
1735 | } | ||
1736 | |||
1737 | static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi, | ||
1738 | struct hpi_control *hpi_ctl) | ||
1739 | { | ||
1740 | struct snd_card *card = asihpi->card; | ||
1741 | struct snd_kcontrol_new snd_control; | ||
1742 | |||
1743 | asihpi_ctl_init(&snd_control, hpi_ctl, "format"); | ||
1744 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
1745 | snd_control.info = snd_asihpi_aesebu_format_info; | ||
1746 | snd_control.get = snd_asihpi_aesebu_rx_format_get; | ||
1747 | snd_control.put = snd_asihpi_aesebu_rx_format_put; | ||
1748 | |||
1749 | |||
1750 | if (ctl_add(card, &snd_control, asihpi) < 0) | ||
1751 | return -EINVAL; | ||
1752 | |||
1753 | asihpi_ctl_init(&snd_control, hpi_ctl, "status"); | ||
1754 | snd_control.access = | ||
1755 | SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ; | ||
1756 | snd_control.info = snd_asihpi_aesebu_rxstatus_info; | ||
1757 | snd_control.get = snd_asihpi_aesebu_rxstatus_get; | ||
1758 | |||
1759 | return ctl_add(card, &snd_control, asihpi); | ||
1760 | } | ||
1761 | |||
1762 | static int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol, | ||
1763 | struct snd_ctl_elem_value *ucontrol) { | ||
1764 | return snd_asihpi_aesebu_format_get(kcontrol, ucontrol, | ||
1765 | HPI_AESEBU__transmitter_get_format); | ||
1766 | } | ||
1767 | |||
1768 | static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol, | ||
1769 | struct snd_ctl_elem_value *ucontrol) { | ||
1770 | return snd_asihpi_aesebu_format_put(kcontrol, ucontrol, | ||
1771 | HPI_AESEBU__transmitter_set_format); | ||
1772 | } | ||
1773 | |||
1774 | |||
1775 | static int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi, | ||
1776 | struct hpi_control *hpi_ctl) | ||
1777 | { | ||
1778 | struct snd_card *card = asihpi->card; | ||
1779 | struct snd_kcontrol_new snd_control; | ||
1780 | |||
1781 | asihpi_ctl_init(&snd_control, hpi_ctl, "format"); | ||
1782 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
1783 | snd_control.info = snd_asihpi_aesebu_format_info; | ||
1784 | snd_control.get = snd_asihpi_aesebu_tx_format_get; | ||
1785 | snd_control.put = snd_asihpi_aesebu_tx_format_put; | ||
1786 | |||
1787 | return ctl_add(card, &snd_control, asihpi); | ||
1788 | } | ||
1789 | |||
1790 | /*------------------------------------------------------------ | ||
1791 | Tuner controls | ||
1792 | ------------------------------------------------------------*/ | ||
1793 | |||
1794 | /* Gain */ | ||
1795 | |||
1796 | static int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol, | ||
1797 | struct snd_ctl_elem_info *uinfo) | ||
1798 | { | ||
1799 | u32 h_control = kcontrol->private_value; | ||
1800 | u16 err; | ||
1801 | short idx; | ||
1802 | u16 gain_range[3]; | ||
1803 | |||
1804 | for (idx = 0; idx < 3; idx++) { | ||
1805 | err = hpi_tuner_query_gain(ss, h_control, | ||
1806 | idx, &gain_range[idx]); | ||
1807 | if (err != 0) | ||
1808 | return err; | ||
1809 | } | ||
1810 | |||
1811 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1812 | uinfo->count = 1; | ||
1813 | uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB; | ||
1814 | uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB; | ||
1815 | uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB; | ||
1816 | return 0; | ||
1817 | } | ||
1818 | |||
1819 | static int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol, | ||
1820 | struct snd_ctl_elem_value *ucontrol) | ||
1821 | { | ||
1822 | /* | ||
1823 | struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol); | ||
1824 | */ | ||
1825 | u32 h_control = kcontrol->private_value; | ||
1826 | short gain; | ||
1827 | |||
1828 | hpi_handle_error(hpi_tuner_get_gain(ss, h_control, &gain)); | ||
1829 | ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB; | ||
1830 | |||
1831 | return 0; | ||
1832 | } | ||
1833 | |||
1834 | static int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol, | ||
1835 | struct snd_ctl_elem_value *ucontrol) | ||
1836 | { | ||
1837 | /* | ||
1838 | struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol); | ||
1839 | */ | ||
1840 | u32 h_control = kcontrol->private_value; | ||
1841 | short gain; | ||
1842 | |||
1843 | gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB; | ||
1844 | hpi_handle_error(hpi_tuner_set_gain(ss, h_control, gain)); | ||
1845 | |||
1846 | return 1; | ||
1847 | } | ||
1848 | |||
1849 | /* Band */ | ||
1850 | |||
1851 | static int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol, | ||
1852 | u16 *band_list, u32 len) { | ||
1853 | u32 h_control = kcontrol->private_value; | ||
1854 | u16 err = 0; | ||
1855 | u32 i; | ||
1856 | |||
1857 | for (i = 0; i < len; i++) { | ||
1858 | err = hpi_tuner_query_band(ss, | ||
1859 | h_control, i, &band_list[i]); | ||
1860 | if (err != 0) | ||
1861 | break; | ||
1862 | } | ||
1863 | |||
1864 | if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX)) | ||
1865 | return -EIO; | ||
1866 | |||
1867 | return i; | ||
1868 | } | ||
1869 | |||
1870 | static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol, | ||
1871 | struct snd_ctl_elem_info *uinfo) | ||
1872 | { | ||
1873 | u16 tuner_bands[HPI_TUNER_BAND_LAST]; | ||
1874 | int num_bands = 0; | ||
1875 | |||
1876 | num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands, | ||
1877 | HPI_TUNER_BAND_LAST); | ||
1878 | |||
1879 | if (num_bands < 0) | ||
1880 | return num_bands; | ||
1881 | |||
1882 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1883 | uinfo->count = 1; | ||
1884 | uinfo->value.enumerated.items = num_bands; | ||
1885 | |||
1886 | if (num_bands > 0) { | ||
1887 | if (uinfo->value.enumerated.item >= | ||
1888 | uinfo->value.enumerated.items) | ||
1889 | uinfo->value.enumerated.item = | ||
1890 | uinfo->value.enumerated.items - 1; | ||
1891 | |||
1892 | strcpy(uinfo->value.enumerated.name, | ||
1893 | asihpi_tuner_band_names[ | ||
1894 | tuner_bands[uinfo->value.enumerated.item]]); | ||
1895 | |||
1896 | } | ||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol, | ||
1901 | struct snd_ctl_elem_value *ucontrol) | ||
1902 | { | ||
1903 | u32 h_control = kcontrol->private_value; | ||
1904 | /* | ||
1905 | struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol); | ||
1906 | */ | ||
1907 | u16 band, idx; | ||
1908 | u16 tuner_bands[HPI_TUNER_BAND_LAST]; | ||
1909 | u32 num_bands = 0; | ||
1910 | |||
1911 | num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands, | ||
1912 | HPI_TUNER_BAND_LAST); | ||
1913 | |||
1914 | hpi_handle_error(hpi_tuner_get_band(ss, h_control, &band)); | ||
1915 | |||
1916 | ucontrol->value.enumerated.item[0] = -1; | ||
1917 | for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++) | ||
1918 | if (tuner_bands[idx] == band) { | ||
1919 | ucontrol->value.enumerated.item[0] = idx; | ||
1920 | break; | ||
1921 | } | ||
1922 | |||
1923 | return 0; | ||
1924 | } | ||
1925 | |||
1926 | static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol, | ||
1927 | struct snd_ctl_elem_value *ucontrol) | ||
1928 | { | ||
1929 | /* | ||
1930 | struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol); | ||
1931 | */ | ||
1932 | u32 h_control = kcontrol->private_value; | ||
1933 | u16 band; | ||
1934 | u16 tuner_bands[HPI_TUNER_BAND_LAST]; | ||
1935 | u32 num_bands = 0; | ||
1936 | |||
1937 | num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands, | ||
1938 | HPI_TUNER_BAND_LAST); | ||
1939 | |||
1940 | band = tuner_bands[ucontrol->value.enumerated.item[0]]; | ||
1941 | hpi_handle_error(hpi_tuner_set_band(ss, h_control, band)); | ||
1942 | |||
1943 | return 1; | ||
1944 | } | ||
1945 | |||
1946 | /* Freq */ | ||
1947 | |||
1948 | static int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol, | ||
1949 | struct snd_ctl_elem_info *uinfo) | ||
1950 | { | ||
1951 | u32 h_control = kcontrol->private_value; | ||
1952 | u16 err; | ||
1953 | u16 tuner_bands[HPI_TUNER_BAND_LAST]; | ||
1954 | u16 num_bands = 0, band_iter, idx; | ||
1955 | u32 freq_range[3], temp_freq_range[3]; | ||
1956 | |||
1957 | num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands, | ||
1958 | HPI_TUNER_BAND_LAST); | ||
1959 | |||
1960 | freq_range[0] = INT_MAX; | ||
1961 | freq_range[1] = 0; | ||
1962 | freq_range[2] = INT_MAX; | ||
1963 | |||
1964 | for (band_iter = 0; band_iter < num_bands; band_iter++) { | ||
1965 | for (idx = 0; idx < 3; idx++) { | ||
1966 | err = hpi_tuner_query_frequency(ss, h_control, | ||
1967 | idx, tuner_bands[band_iter], | ||
1968 | &temp_freq_range[idx]); | ||
1969 | if (err != 0) | ||
1970 | return err; | ||
1971 | } | ||
1972 | |||
1973 | /* skip band with bogus stepping */ | ||
1974 | if (temp_freq_range[2] <= 0) | ||
1975 | continue; | ||
1976 | |||
1977 | if (temp_freq_range[0] < freq_range[0]) | ||
1978 | freq_range[0] = temp_freq_range[0]; | ||
1979 | if (temp_freq_range[1] > freq_range[1]) | ||
1980 | freq_range[1] = temp_freq_range[1]; | ||
1981 | if (temp_freq_range[2] < freq_range[2]) | ||
1982 | freq_range[2] = temp_freq_range[2]; | ||
1983 | } | ||
1984 | |||
1985 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1986 | uinfo->count = 1; | ||
1987 | uinfo->value.integer.min = ((int)freq_range[0]); | ||
1988 | uinfo->value.integer.max = ((int)freq_range[1]); | ||
1989 | uinfo->value.integer.step = ((int)freq_range[2]); | ||
1990 | return 0; | ||
1991 | } | ||
1992 | |||
1993 | static int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol, | ||
1994 | struct snd_ctl_elem_value *ucontrol) | ||
1995 | { | ||
1996 | u32 h_control = kcontrol->private_value; | ||
1997 | u32 freq; | ||
1998 | |||
1999 | hpi_handle_error(hpi_tuner_get_frequency(ss, h_control, &freq)); | ||
2000 | ucontrol->value.integer.value[0] = freq; | ||
2001 | |||
2002 | return 0; | ||
2003 | } | ||
2004 | |||
2005 | static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol, | ||
2006 | struct snd_ctl_elem_value *ucontrol) | ||
2007 | { | ||
2008 | u32 h_control = kcontrol->private_value; | ||
2009 | u32 freq; | ||
2010 | |||
2011 | freq = ucontrol->value.integer.value[0]; | ||
2012 | hpi_handle_error(hpi_tuner_set_frequency(ss, h_control, freq)); | ||
2013 | |||
2014 | return 1; | ||
2015 | } | ||
2016 | |||
2017 | /* Tuner control group initializer */ | ||
2018 | static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi, | ||
2019 | struct hpi_control *hpi_ctl) | ||
2020 | { | ||
2021 | struct snd_card *card = asihpi->card; | ||
2022 | struct snd_kcontrol_new snd_control; | ||
2023 | |||
2024 | snd_control.private_value = hpi_ctl->h_control; | ||
2025 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
2026 | |||
2027 | if (!hpi_tuner_get_gain(ss, hpi_ctl->h_control, NULL)) { | ||
2028 | asihpi_ctl_init(&snd_control, hpi_ctl, "gain"); | ||
2029 | snd_control.info = snd_asihpi_tuner_gain_info; | ||
2030 | snd_control.get = snd_asihpi_tuner_gain_get; | ||
2031 | snd_control.put = snd_asihpi_tuner_gain_put; | ||
2032 | |||
2033 | if (ctl_add(card, &snd_control, asihpi) < 0) | ||
2034 | return -EINVAL; | ||
2035 | } | ||
2036 | |||
2037 | asihpi_ctl_init(&snd_control, hpi_ctl, "band"); | ||
2038 | snd_control.info = snd_asihpi_tuner_band_info; | ||
2039 | snd_control.get = snd_asihpi_tuner_band_get; | ||
2040 | snd_control.put = snd_asihpi_tuner_band_put; | ||
2041 | |||
2042 | if (ctl_add(card, &snd_control, asihpi) < 0) | ||
2043 | return -EINVAL; | ||
2044 | |||
2045 | asihpi_ctl_init(&snd_control, hpi_ctl, "freq"); | ||
2046 | snd_control.info = snd_asihpi_tuner_freq_info; | ||
2047 | snd_control.get = snd_asihpi_tuner_freq_get; | ||
2048 | snd_control.put = snd_asihpi_tuner_freq_put; | ||
2049 | |||
2050 | return ctl_add(card, &snd_control, asihpi); | ||
2051 | } | ||
2052 | |||
2053 | /*------------------------------------------------------------ | ||
2054 | Meter controls | ||
2055 | ------------------------------------------------------------*/ | ||
2056 | static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol, | ||
2057 | struct snd_ctl_elem_info *uinfo) | ||
2058 | { | ||
2059 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2060 | uinfo->count = HPI_MAX_CHANNELS; | ||
2061 | uinfo->value.integer.min = 0; | ||
2062 | uinfo->value.integer.max = 0x7FFFFFFF; | ||
2063 | return 0; | ||
2064 | } | ||
2065 | |||
2066 | /* linear values for 10dB steps */ | ||
2067 | static int log2lin[] = { | ||
2068 | 0x7FFFFFFF, /* 0dB */ | ||
2069 | 679093956, | ||
2070 | 214748365, | ||
2071 | 67909396, | ||
2072 | 21474837, | ||
2073 | 6790940, | ||
2074 | 2147484, /* -60dB */ | ||
2075 | 679094, | ||
2076 | 214748, /* -80 */ | ||
2077 | 67909, | ||
2078 | 21475, /* -100 */ | ||
2079 | 6791, | ||
2080 | 2147, | ||
2081 | 679, | ||
2082 | 214, | ||
2083 | 68, | ||
2084 | 21, | ||
2085 | 7, | ||
2086 | 2 | ||
2087 | }; | ||
2088 | |||
2089 | static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol, | ||
2090 | struct snd_ctl_elem_value *ucontrol) | ||
2091 | { | ||
2092 | u32 h_control = kcontrol->private_value; | ||
2093 | short an_gain_mB[HPI_MAX_CHANNELS], i; | ||
2094 | u16 err; | ||
2095 | |||
2096 | err = hpi_meter_get_peak(ss, h_control, an_gain_mB); | ||
2097 | |||
2098 | for (i = 0; i < HPI_MAX_CHANNELS; i++) { | ||
2099 | if (err) { | ||
2100 | ucontrol->value.integer.value[i] = 0; | ||
2101 | } else if (an_gain_mB[i] >= 0) { | ||
2102 | ucontrol->value.integer.value[i] = | ||
2103 | an_gain_mB[i] << 16; | ||
2104 | } else { | ||
2105 | /* -ve is log value in millibels < -60dB, | ||
2106 | * convert to (roughly!) linear, | ||
2107 | */ | ||
2108 | ucontrol->value.integer.value[i] = | ||
2109 | log2lin[an_gain_mB[i] / -1000]; | ||
2110 | } | ||
2111 | } | ||
2112 | return 0; | ||
2113 | } | ||
2114 | |||
2115 | static int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi, | ||
2116 | struct hpi_control *hpi_ctl, int subidx) | ||
2117 | { | ||
2118 | struct snd_card *card = asihpi->card; | ||
2119 | struct snd_kcontrol_new snd_control; | ||
2120 | |||
2121 | asihpi_ctl_init(&snd_control, hpi_ctl, "meter"); | ||
2122 | snd_control.access = | ||
2123 | SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ; | ||
2124 | snd_control.info = snd_asihpi_meter_info; | ||
2125 | snd_control.get = snd_asihpi_meter_get; | ||
2126 | |||
2127 | snd_control.index = subidx; | ||
2128 | |||
2129 | return ctl_add(card, &snd_control, asihpi); | ||
2130 | } | ||
2131 | |||
2132 | /*------------------------------------------------------------ | ||
2133 | Multiplexer controls | ||
2134 | ------------------------------------------------------------*/ | ||
2135 | static int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control) | ||
2136 | { | ||
2137 | u32 h_control = snd_control->private_value; | ||
2138 | struct hpi_control hpi_ctl; | ||
2139 | int s, err; | ||
2140 | for (s = 0; s < 32; s++) { | ||
2141 | err = hpi_multiplexer_query_source(ss, h_control, s, | ||
2142 | &hpi_ctl. | ||
2143 | src_node_type, | ||
2144 | &hpi_ctl. | ||
2145 | src_node_index); | ||
2146 | if (err) | ||
2147 | break; | ||
2148 | } | ||
2149 | return s; | ||
2150 | } | ||
2151 | |||
2152 | static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol, | ||
2153 | struct snd_ctl_elem_info *uinfo) | ||
2154 | { | ||
2155 | int err; | ||
2156 | u16 src_node_type, src_node_index; | ||
2157 | u32 h_control = kcontrol->private_value; | ||
2158 | |||
2159 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2160 | uinfo->count = 1; | ||
2161 | uinfo->value.enumerated.items = | ||
2162 | snd_card_asihpi_mux_count_sources(kcontrol); | ||
2163 | |||
2164 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2165 | uinfo->value.enumerated.item = | ||
2166 | uinfo->value.enumerated.items - 1; | ||
2167 | |||
2168 | err = | ||
2169 | hpi_multiplexer_query_source(ss, h_control, | ||
2170 | uinfo->value.enumerated.item, | ||
2171 | &src_node_type, &src_node_index); | ||
2172 | |||
2173 | sprintf(uinfo->value.enumerated.name, "%s %d", | ||
2174 | asihpi_src_names[src_node_type - HPI_SOURCENODE_BASE], | ||
2175 | src_node_index); | ||
2176 | return 0; | ||
2177 | } | ||
2178 | |||
2179 | static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol, | ||
2180 | struct snd_ctl_elem_value *ucontrol) | ||
2181 | { | ||
2182 | u32 h_control = kcontrol->private_value; | ||
2183 | u16 source_type, source_index; | ||
2184 | u16 src_node_type, src_node_index; | ||
2185 | int s; | ||
2186 | |||
2187 | hpi_handle_error(hpi_multiplexer_get_source(ss, h_control, | ||
2188 | &source_type, &source_index)); | ||
2189 | /* Should cache this search result! */ | ||
2190 | for (s = 0; s < 256; s++) { | ||
2191 | if (hpi_multiplexer_query_source(ss, h_control, s, | ||
2192 | &src_node_type, &src_node_index)) | ||
2193 | break; | ||
2194 | |||
2195 | if ((source_type == src_node_type) | ||
2196 | && (source_index == src_node_index)) { | ||
2197 | ucontrol->value.enumerated.item[0] = s; | ||
2198 | return 0; | ||
2199 | } | ||
2200 | } | ||
2201 | snd_printd(KERN_WARNING | ||
2202 | "control %x failed to match mux source %hu %hu\n", | ||
2203 | h_control, source_type, source_index); | ||
2204 | ucontrol->value.enumerated.item[0] = 0; | ||
2205 | return 0; | ||
2206 | } | ||
2207 | |||
2208 | static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol, | ||
2209 | struct snd_ctl_elem_value *ucontrol) | ||
2210 | { | ||
2211 | int change; | ||
2212 | u32 h_control = kcontrol->private_value; | ||
2213 | u16 source_type, source_index; | ||
2214 | u16 e; | ||
2215 | |||
2216 | change = 1; | ||
2217 | |||
2218 | e = hpi_multiplexer_query_source(ss, h_control, | ||
2219 | ucontrol->value.enumerated.item[0], | ||
2220 | &source_type, &source_index); | ||
2221 | if (!e) | ||
2222 | hpi_handle_error( | ||
2223 | hpi_multiplexer_set_source(ss, h_control, | ||
2224 | source_type, source_index)); | ||
2225 | return change; | ||
2226 | } | ||
2227 | |||
2228 | |||
2229 | static int __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi, | ||
2230 | struct hpi_control *hpi_ctl) | ||
2231 | { | ||
2232 | struct snd_card *card = asihpi->card; | ||
2233 | struct snd_kcontrol_new snd_control; | ||
2234 | |||
2235 | #if ASI_STYLE_NAMES | ||
2236 | asihpi_ctl_init(&snd_control, hpi_ctl, "multiplexer"); | ||
2237 | #else | ||
2238 | asihpi_ctl_init(&snd_control, hpi_ctl, "route"); | ||
2239 | #endif | ||
2240 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
2241 | snd_control.info = snd_asihpi_mux_info; | ||
2242 | snd_control.get = snd_asihpi_mux_get; | ||
2243 | snd_control.put = snd_asihpi_mux_put; | ||
2244 | |||
2245 | return ctl_add(card, &snd_control, asihpi); | ||
2246 | |||
2247 | } | ||
2248 | |||
2249 | /*------------------------------------------------------------ | ||
2250 | Channel mode controls | ||
2251 | ------------------------------------------------------------*/ | ||
2252 | static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol, | ||
2253 | struct snd_ctl_elem_info *uinfo) | ||
2254 | { | ||
2255 | static char *mode_names[HPI_CHANNEL_MODE_LAST] = { | ||
2256 | "normal", "swap", | ||
2257 | "from_left", "from_right", | ||
2258 | "to_left", "to_right" | ||
2259 | }; | ||
2260 | |||
2261 | u32 h_control = kcontrol->private_value; | ||
2262 | u16 mode; | ||
2263 | int i; | ||
2264 | |||
2265 | /* HPI channel mode values can be from 1 to 6 | ||
2266 | Some adapters only support a contiguous subset | ||
2267 | */ | ||
2268 | for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++) | ||
2269 | if (hpi_channel_mode_query_mode( | ||
2270 | ss, h_control, i, &mode)) | ||
2271 | break; | ||
2272 | |||
2273 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2274 | uinfo->count = 1; | ||
2275 | uinfo->value.enumerated.items = i; | ||
2276 | |||
2277 | if (uinfo->value.enumerated.item >= i) | ||
2278 | uinfo->value.enumerated.item = i - 1; | ||
2279 | |||
2280 | strcpy(uinfo->value.enumerated.name, | ||
2281 | mode_names[uinfo->value.enumerated.item]); | ||
2282 | |||
2283 | return 0; | ||
2284 | } | ||
2285 | |||
2286 | static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol, | ||
2287 | struct snd_ctl_elem_value *ucontrol) | ||
2288 | { | ||
2289 | u32 h_control = kcontrol->private_value; | ||
2290 | u16 mode; | ||
2291 | |||
2292 | if (hpi_channel_mode_get(ss, h_control, &mode)) | ||
2293 | mode = 1; | ||
2294 | |||
2295 | ucontrol->value.enumerated.item[0] = mode - 1; | ||
2296 | |||
2297 | return 0; | ||
2298 | } | ||
2299 | |||
2300 | static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol, | ||
2301 | struct snd_ctl_elem_value *ucontrol) | ||
2302 | { | ||
2303 | int change; | ||
2304 | u32 h_control = kcontrol->private_value; | ||
2305 | |||
2306 | change = 1; | ||
2307 | |||
2308 | hpi_handle_error(hpi_channel_mode_set(ss, h_control, | ||
2309 | ucontrol->value.enumerated.item[0] + 1)); | ||
2310 | return change; | ||
2311 | } | ||
2312 | |||
2313 | |||
2314 | static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi, | ||
2315 | struct hpi_control *hpi_ctl) | ||
2316 | { | ||
2317 | struct snd_card *card = asihpi->card; | ||
2318 | struct snd_kcontrol_new snd_control; | ||
2319 | |||
2320 | asihpi_ctl_init(&snd_control, hpi_ctl, "channel mode"); | ||
2321 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
2322 | snd_control.info = snd_asihpi_cmode_info; | ||
2323 | snd_control.get = snd_asihpi_cmode_get; | ||
2324 | snd_control.put = snd_asihpi_cmode_put; | ||
2325 | |||
2326 | return ctl_add(card, &snd_control, asihpi); | ||
2327 | } | ||
2328 | |||
2329 | /*------------------------------------------------------------ | ||
2330 | Sampleclock source controls | ||
2331 | ------------------------------------------------------------*/ | ||
2332 | |||
2333 | static char *sampleclock_sources[MAX_CLOCKSOURCES] = | ||
2334 | { "N/A", "local PLL", "AES/EBU sync", "word external", "word header", | ||
2335 | "SMPTE", "AES/EBU in1", "auto", "network", "invalid", | ||
2336 | "prev module", | ||
2337 | "AES/EBU in2", "AES/EBU in3", "AES/EBU in4", "AES/EBU in5", | ||
2338 | "AES/EBU in6", "AES/EBU in7", "AES/EBU in8"}; | ||
2339 | |||
2340 | |||
2341 | |||
2342 | static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol, | ||
2343 | struct snd_ctl_elem_info *uinfo) | ||
2344 | { | ||
2345 | struct snd_card_asihpi *asihpi = | ||
2346 | (struct snd_card_asihpi *)(kcontrol->private_data); | ||
2347 | struct clk_cache *clkcache = &asihpi->cc; | ||
2348 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2349 | uinfo->count = 1; | ||
2350 | uinfo->value.enumerated.items = clkcache->count; | ||
2351 | |||
2352 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2353 | uinfo->value.enumerated.item = | ||
2354 | uinfo->value.enumerated.items - 1; | ||
2355 | |||
2356 | strcpy(uinfo->value.enumerated.name, | ||
2357 | clkcache->s[uinfo->value.enumerated.item].name); | ||
2358 | return 0; | ||
2359 | } | ||
2360 | |||
2361 | static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol, | ||
2362 | struct snd_ctl_elem_value *ucontrol) | ||
2363 | { | ||
2364 | struct snd_card_asihpi *asihpi = | ||
2365 | (struct snd_card_asihpi *)(kcontrol->private_data); | ||
2366 | struct clk_cache *clkcache = &asihpi->cc; | ||
2367 | u32 h_control = kcontrol->private_value; | ||
2368 | u16 source, srcindex = 0; | ||
2369 | int i; | ||
2370 | |||
2371 | ucontrol->value.enumerated.item[0] = 0; | ||
2372 | if (hpi_sample_clock_get_source(ss, h_control, &source)) | ||
2373 | source = 0; | ||
2374 | |||
2375 | if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT) | ||
2376 | if (hpi_sample_clock_get_source_index(ss, h_control, &srcindex)) | ||
2377 | srcindex = 0; | ||
2378 | |||
2379 | for (i = 0; i < clkcache->count; i++) | ||
2380 | if ((clkcache->s[i].source == source) && | ||
2381 | (clkcache->s[i].index == srcindex)) | ||
2382 | break; | ||
2383 | |||
2384 | ucontrol->value.enumerated.item[0] = i; | ||
2385 | |||
2386 | return 0; | ||
2387 | } | ||
2388 | |||
2389 | static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol, | ||
2390 | struct snd_ctl_elem_value *ucontrol) | ||
2391 | { | ||
2392 | struct snd_card_asihpi *asihpi = | ||
2393 | (struct snd_card_asihpi *)(kcontrol->private_data); | ||
2394 | struct clk_cache *clkcache = &asihpi->cc; | ||
2395 | int change, item; | ||
2396 | u32 h_control = kcontrol->private_value; | ||
2397 | |||
2398 | change = 1; | ||
2399 | item = ucontrol->value.enumerated.item[0]; | ||
2400 | if (item >= clkcache->count) | ||
2401 | item = clkcache->count-1; | ||
2402 | |||
2403 | hpi_handle_error(hpi_sample_clock_set_source(ss, | ||
2404 | h_control, clkcache->s[item].source)); | ||
2405 | |||
2406 | if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT) | ||
2407 | hpi_handle_error(hpi_sample_clock_set_source_index(ss, | ||
2408 | h_control, clkcache->s[item].index)); | ||
2409 | return change; | ||
2410 | } | ||
2411 | |||
2412 | /*------------------------------------------------------------ | ||
2413 | Clkrate controls | ||
2414 | ------------------------------------------------------------*/ | ||
2415 | /* Need to change this to enumerated control with list of rates */ | ||
2416 | static int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol, | ||
2417 | struct snd_ctl_elem_info *uinfo) | ||
2418 | { | ||
2419 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2420 | uinfo->count = 1; | ||
2421 | uinfo->value.integer.min = 8000; | ||
2422 | uinfo->value.integer.max = 192000; | ||
2423 | uinfo->value.integer.step = 100; | ||
2424 | |||
2425 | return 0; | ||
2426 | } | ||
2427 | |||
2428 | static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol, | ||
2429 | struct snd_ctl_elem_value *ucontrol) | ||
2430 | { | ||
2431 | u32 h_control = kcontrol->private_value; | ||
2432 | u32 rate; | ||
2433 | u16 e; | ||
2434 | |||
2435 | e = hpi_sample_clock_get_local_rate(ss, h_control, &rate); | ||
2436 | if (!e) | ||
2437 | ucontrol->value.integer.value[0] = rate; | ||
2438 | else | ||
2439 | ucontrol->value.integer.value[0] = 0; | ||
2440 | return 0; | ||
2441 | } | ||
2442 | |||
2443 | static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol, | ||
2444 | struct snd_ctl_elem_value *ucontrol) | ||
2445 | { | ||
2446 | int change; | ||
2447 | u32 h_control = kcontrol->private_value; | ||
2448 | |||
2449 | /* change = asihpi->mixer_clkrate[addr][0] != left || | ||
2450 | asihpi->mixer_clkrate[addr][1] != right; | ||
2451 | */ | ||
2452 | change = 1; | ||
2453 | hpi_handle_error(hpi_sample_clock_set_local_rate(ss, h_control, | ||
2454 | ucontrol->value.integer.value[0])); | ||
2455 | return change; | ||
2456 | } | ||
2457 | |||
2458 | static int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol, | ||
2459 | struct snd_ctl_elem_info *uinfo) | ||
2460 | { | ||
2461 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2462 | uinfo->count = 1; | ||
2463 | uinfo->value.integer.min = 8000; | ||
2464 | uinfo->value.integer.max = 192000; | ||
2465 | uinfo->value.integer.step = 100; | ||
2466 | |||
2467 | return 0; | ||
2468 | } | ||
2469 | |||
2470 | static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol, | ||
2471 | struct snd_ctl_elem_value *ucontrol) | ||
2472 | { | ||
2473 | u32 h_control = kcontrol->private_value; | ||
2474 | u32 rate; | ||
2475 | u16 e; | ||
2476 | |||
2477 | e = hpi_sample_clock_get_sample_rate(ss, h_control, &rate); | ||
2478 | if (!e) | ||
2479 | ucontrol->value.integer.value[0] = rate; | ||
2480 | else | ||
2481 | ucontrol->value.integer.value[0] = 0; | ||
2482 | return 0; | ||
2483 | } | ||
2484 | |||
2485 | static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, | ||
2486 | struct hpi_control *hpi_ctl) | ||
2487 | { | ||
2488 | struct snd_card *card = asihpi->card; | ||
2489 | struct snd_kcontrol_new snd_control; | ||
2490 | |||
2491 | struct clk_cache *clkcache = &asihpi->cc; | ||
2492 | u32 hSC = hpi_ctl->h_control; | ||
2493 | int has_aes_in = 0; | ||
2494 | int i, j; | ||
2495 | u16 source; | ||
2496 | |||
2497 | snd_control.private_value = hpi_ctl->h_control; | ||
2498 | |||
2499 | clkcache->has_local = 0; | ||
2500 | |||
2501 | for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) { | ||
2502 | if (hpi_sample_clock_query_source(ss, hSC, | ||
2503 | i, &source)) | ||
2504 | break; | ||
2505 | clkcache->s[i].source = source; | ||
2506 | clkcache->s[i].index = 0; | ||
2507 | clkcache->s[i].name = sampleclock_sources[source]; | ||
2508 | if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT) | ||
2509 | has_aes_in = 1; | ||
2510 | if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL) | ||
2511 | clkcache->has_local = 1; | ||
2512 | } | ||
2513 | if (has_aes_in) | ||
2514 | /* already will have picked up index 0 above */ | ||
2515 | for (j = 1; j < 8; j++) { | ||
2516 | if (hpi_sample_clock_query_source_index(ss, hSC, | ||
2517 | j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT, | ||
2518 | &source)) | ||
2519 | break; | ||
2520 | clkcache->s[i].source = | ||
2521 | HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT; | ||
2522 | clkcache->s[i].index = j; | ||
2523 | clkcache->s[i].name = sampleclock_sources[ | ||
2524 | j+HPI_SAMPLECLOCK_SOURCE_LAST]; | ||
2525 | i++; | ||
2526 | } | ||
2527 | clkcache->count = i; | ||
2528 | |||
2529 | asihpi_ctl_init(&snd_control, hpi_ctl, "source"); | ||
2530 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ; | ||
2531 | snd_control.info = snd_asihpi_clksrc_info; | ||
2532 | snd_control.get = snd_asihpi_clksrc_get; | ||
2533 | snd_control.put = snd_asihpi_clksrc_put; | ||
2534 | if (ctl_add(card, &snd_control, asihpi) < 0) | ||
2535 | return -EINVAL; | ||
2536 | |||
2537 | |||
2538 | if (clkcache->has_local) { | ||
2539 | asihpi_ctl_init(&snd_control, hpi_ctl, "local_rate"); | ||
2540 | snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ; | ||
2541 | snd_control.info = snd_asihpi_clklocal_info; | ||
2542 | snd_control.get = snd_asihpi_clklocal_get; | ||
2543 | snd_control.put = snd_asihpi_clklocal_put; | ||
2544 | |||
2545 | |||
2546 | if (ctl_add(card, &snd_control, asihpi) < 0) | ||
2547 | return -EINVAL; | ||
2548 | } | ||
2549 | |||
2550 | asihpi_ctl_init(&snd_control, hpi_ctl, "rate"); | ||
2551 | snd_control.access = | ||
2552 | SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ; | ||
2553 | snd_control.info = snd_asihpi_clkrate_info; | ||
2554 | snd_control.get = snd_asihpi_clkrate_get; | ||
2555 | |||
2556 | return ctl_add(card, &snd_control, asihpi); | ||
2557 | } | ||
2558 | /*------------------------------------------------------------ | ||
2559 | Mixer | ||
2560 | ------------------------------------------------------------*/ | ||
2561 | |||
2562 | static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) | ||
2563 | { | ||
2564 | struct snd_card *card = asihpi->card; | ||
2565 | unsigned int idx = 0; | ||
2566 | unsigned int subindex = 0; | ||
2567 | int err; | ||
2568 | struct hpi_control hpi_ctl, prev_ctl; | ||
2569 | |||
2570 | if (snd_BUG_ON(!asihpi)) | ||
2571 | return -EINVAL; | ||
2572 | strcpy(card->mixername, "asihpi mixer"); | ||
2573 | |||
2574 | err = | ||
2575 | hpi_mixer_open(ss, asihpi->adapter_index, | ||
2576 | &asihpi->h_mixer); | ||
2577 | hpi_handle_error(err); | ||
2578 | if (err) | ||
2579 | return -err; | ||
2580 | |||
2581 | for (idx = 0; idx < 2000; idx++) { | ||
2582 | err = hpi_mixer_get_control_by_index( | ||
2583 | ss, asihpi->h_mixer, | ||
2584 | idx, | ||
2585 | &hpi_ctl.src_node_type, | ||
2586 | &hpi_ctl.src_node_index, | ||
2587 | &hpi_ctl.dst_node_type, | ||
2588 | &hpi_ctl.dst_node_index, | ||
2589 | &hpi_ctl.control_type, | ||
2590 | &hpi_ctl.h_control); | ||
2591 | if (err) { | ||
2592 | if (err == HPI_ERROR_CONTROL_DISABLED) { | ||
2593 | if (mixer_dump) | ||
2594 | snd_printk(KERN_INFO | ||
2595 | "disabled HPI control(%d)\n", | ||
2596 | idx); | ||
2597 | continue; | ||
2598 | } else | ||
2599 | break; | ||
2600 | |||
2601 | } | ||
2602 | |||
2603 | hpi_ctl.src_node_type -= HPI_SOURCENODE_BASE; | ||
2604 | hpi_ctl.dst_node_type -= HPI_DESTNODE_BASE; | ||
2605 | |||
2606 | /* ASI50xx in SSX mode has multiple meters on the same node. | ||
2607 | Use subindex to create distinct ALSA controls | ||
2608 | for any duplicated controls. | ||
2609 | */ | ||
2610 | if ((hpi_ctl.control_type == prev_ctl.control_type) && | ||
2611 | (hpi_ctl.src_node_type == prev_ctl.src_node_type) && | ||
2612 | (hpi_ctl.src_node_index == prev_ctl.src_node_index) && | ||
2613 | (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) && | ||
2614 | (hpi_ctl.dst_node_index == prev_ctl.dst_node_index)) | ||
2615 | subindex++; | ||
2616 | else | ||
2617 | subindex = 0; | ||
2618 | |||
2619 | prev_ctl = hpi_ctl; | ||
2620 | |||
2621 | switch (hpi_ctl.control_type) { | ||
2622 | case HPI_CONTROL_VOLUME: | ||
2623 | err = snd_asihpi_volume_add(asihpi, &hpi_ctl); | ||
2624 | break; | ||
2625 | case HPI_CONTROL_LEVEL: | ||
2626 | err = snd_asihpi_level_add(asihpi, &hpi_ctl); | ||
2627 | break; | ||
2628 | case HPI_CONTROL_MULTIPLEXER: | ||
2629 | err = snd_asihpi_mux_add(asihpi, &hpi_ctl); | ||
2630 | break; | ||
2631 | case HPI_CONTROL_CHANNEL_MODE: | ||
2632 | err = snd_asihpi_cmode_add(asihpi, &hpi_ctl); | ||
2633 | break; | ||
2634 | case HPI_CONTROL_METER: | ||
2635 | err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex); | ||
2636 | break; | ||
2637 | case HPI_CONTROL_SAMPLECLOCK: | ||
2638 | err = snd_asihpi_sampleclock_add( | ||
2639 | asihpi, &hpi_ctl); | ||
2640 | break; | ||
2641 | case HPI_CONTROL_CONNECTION: /* ignore these */ | ||
2642 | continue; | ||
2643 | case HPI_CONTROL_TUNER: | ||
2644 | err = snd_asihpi_tuner_add(asihpi, &hpi_ctl); | ||
2645 | break; | ||
2646 | case HPI_CONTROL_AESEBU_TRANSMITTER: | ||
2647 | err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl); | ||
2648 | break; | ||
2649 | case HPI_CONTROL_AESEBU_RECEIVER: | ||
2650 | err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl); | ||
2651 | break; | ||
2652 | case HPI_CONTROL_VOX: | ||
2653 | case HPI_CONTROL_BITSTREAM: | ||
2654 | case HPI_CONTROL_MICROPHONE: | ||
2655 | case HPI_CONTROL_PARAMETRIC_EQ: | ||
2656 | case HPI_CONTROL_COMPANDER: | ||
2657 | default: | ||
2658 | if (mixer_dump) | ||
2659 | snd_printk(KERN_INFO | ||
2660 | "untranslated HPI control" | ||
2661 | "(%d) %d %d %d %d %d\n", | ||
2662 | idx, | ||
2663 | hpi_ctl.control_type, | ||
2664 | hpi_ctl.src_node_type, | ||
2665 | hpi_ctl.src_node_index, | ||
2666 | hpi_ctl.dst_node_type, | ||
2667 | hpi_ctl.dst_node_index); | ||
2668 | continue; | ||
2669 | }; | ||
2670 | if (err < 0) | ||
2671 | return err; | ||
2672 | } | ||
2673 | if (HPI_ERROR_INVALID_OBJ_INDEX != err) | ||
2674 | hpi_handle_error(err); | ||
2675 | |||
2676 | snd_printk(KERN_INFO "%d mixer controls found\n", idx); | ||
2677 | |||
2678 | return 0; | ||
2679 | } | ||
2680 | |||
2681 | /*------------------------------------------------------------ | ||
2682 | /proc interface | ||
2683 | ------------------------------------------------------------*/ | ||
2684 | |||
2685 | static void | ||
2686 | snd_asihpi_proc_read(struct snd_info_entry *entry, | ||
2687 | struct snd_info_buffer *buffer) | ||
2688 | { | ||
2689 | struct snd_card_asihpi *asihpi = entry->private_data; | ||
2690 | u16 version; | ||
2691 | u32 h_control; | ||
2692 | u32 rate = 0; | ||
2693 | u16 source = 0; | ||
2694 | int err; | ||
2695 | |||
2696 | snd_iprintf(buffer, "ASIHPI driver proc file\n"); | ||
2697 | snd_iprintf(buffer, | ||
2698 | "adapter ID=%4X\n_index=%d\n" | ||
2699 | "num_outstreams=%d\n_num_instreams=%d\n", | ||
2700 | asihpi->type, asihpi->adapter_index, | ||
2701 | asihpi->num_outstreams, asihpi->num_instreams); | ||
2702 | |||
2703 | version = asihpi->version; | ||
2704 | snd_iprintf(buffer, | ||
2705 | "serial#=%d\n_hw version %c%d\nDSP code version %03d\n", | ||
2706 | asihpi->serial_number, ((version >> 3) & 0xf) + 'A', | ||
2707 | version & 0x7, | ||
2708 | ((version >> 13) * 100) + ((version >> 7) & 0x3f)); | ||
2709 | |||
2710 | err = hpi_mixer_get_control(ss, asihpi->h_mixer, | ||
2711 | HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, | ||
2712 | HPI_CONTROL_SAMPLECLOCK, &h_control); | ||
2713 | |||
2714 | if (!err) { | ||
2715 | err = hpi_sample_clock_get_sample_rate(ss, | ||
2716 | h_control, &rate); | ||
2717 | err += hpi_sample_clock_get_source(ss, h_control, &source); | ||
2718 | |||
2719 | if (!err) | ||
2720 | snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n", | ||
2721 | rate, sampleclock_sources[source]); | ||
2722 | } | ||
2723 | |||
2724 | } | ||
2725 | |||
2726 | |||
2727 | static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi) | ||
2728 | { | ||
2729 | struct snd_info_entry *entry; | ||
2730 | |||
2731 | if (!snd_card_proc_new(asihpi->card, "info", &entry)) | ||
2732 | snd_info_set_text_ops(entry, asihpi, snd_asihpi_proc_read); | ||
2733 | } | ||
2734 | |||
2735 | /*------------------------------------------------------------ | ||
2736 | HWDEP | ||
2737 | ------------------------------------------------------------*/ | ||
2738 | |||
2739 | static int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file) | ||
2740 | { | ||
2741 | if (enable_hpi_hwdep) | ||
2742 | return 0; | ||
2743 | else | ||
2744 | return -ENODEV; | ||
2745 | |||
2746 | } | ||
2747 | |||
2748 | static int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file) | ||
2749 | { | ||
2750 | if (enable_hpi_hwdep) | ||
2751 | return asihpi_hpi_release(file); | ||
2752 | else | ||
2753 | return -ENODEV; | ||
2754 | } | ||
2755 | |||
2756 | static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file, | ||
2757 | unsigned int cmd, unsigned long arg) | ||
2758 | { | ||
2759 | if (enable_hpi_hwdep) | ||
2760 | return asihpi_hpi_ioctl(file, cmd, arg); | ||
2761 | else | ||
2762 | return -ENODEV; | ||
2763 | } | ||
2764 | |||
2765 | |||
2766 | /* results in /dev/snd/hwC#D0 file for each card with index # | ||
2767 | also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card' | ||
2768 | */ | ||
2769 | static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, | ||
2770 | int device, struct snd_hwdep **rhwdep) | ||
2771 | { | ||
2772 | struct snd_hwdep *hw; | ||
2773 | int err; | ||
2774 | |||
2775 | if (rhwdep) | ||
2776 | *rhwdep = NULL; | ||
2777 | err = snd_hwdep_new(asihpi->card, "HPI", device, &hw); | ||
2778 | if (err < 0) | ||
2779 | return err; | ||
2780 | strcpy(hw->name, "asihpi (HPI)"); | ||
2781 | hw->iface = SNDRV_HWDEP_IFACE_LAST; | ||
2782 | hw->ops.open = snd_asihpi_hpi_open; | ||
2783 | hw->ops.ioctl = snd_asihpi_hpi_ioctl; | ||
2784 | hw->ops.release = snd_asihpi_hpi_release; | ||
2785 | hw->private_data = asihpi; | ||
2786 | if (rhwdep) | ||
2787 | *rhwdep = hw; | ||
2788 | return 0; | ||
2789 | } | ||
2790 | |||
2791 | /*------------------------------------------------------------ | ||
2792 | CARD | ||
2793 | ------------------------------------------------------------*/ | ||
2794 | static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | ||
2795 | const struct pci_device_id *pci_id) | ||
2796 | { | ||
2797 | int err; | ||
2798 | |||
2799 | u16 version; | ||
2800 | int pcm_substreams; | ||
2801 | |||
2802 | struct hpi_adapter *hpi_card; | ||
2803 | struct snd_card *card; | ||
2804 | struct snd_card_asihpi *asihpi; | ||
2805 | |||
2806 | u32 h_control; | ||
2807 | u32 h_stream; | ||
2808 | |||
2809 | static int dev; | ||
2810 | if (dev >= SNDRV_CARDS) | ||
2811 | return -ENODEV; | ||
2812 | |||
2813 | /* Should this be enable[hpi_card->index] ? */ | ||
2814 | if (!enable[dev]) { | ||
2815 | dev++; | ||
2816 | return -ENOENT; | ||
2817 | } | ||
2818 | |||
2819 | err = asihpi_adapter_probe(pci_dev, pci_id); | ||
2820 | if (err < 0) | ||
2821 | return err; | ||
2822 | |||
2823 | hpi_card = pci_get_drvdata(pci_dev); | ||
2824 | /* first try to give the card the same index as its hardware index */ | ||
2825 | err = snd_card_create(hpi_card->index, | ||
2826 | id[hpi_card->index], THIS_MODULE, | ||
2827 | sizeof(struct snd_card_asihpi), | ||
2828 | &card); | ||
2829 | if (err < 0) { | ||
2830 | /* if that fails, try the default index==next available */ | ||
2831 | err = | ||
2832 | snd_card_create(index[dev], id[dev], | ||
2833 | THIS_MODULE, | ||
2834 | sizeof(struct snd_card_asihpi), | ||
2835 | &card); | ||
2836 | if (err < 0) | ||
2837 | return err; | ||
2838 | snd_printk(KERN_WARNING | ||
2839 | "**** WARNING **** adapter index %d->ALSA index %d\n", | ||
2840 | hpi_card->index, card->number); | ||
2841 | } | ||
2842 | |||
2843 | asihpi = (struct snd_card_asihpi *) card->private_data; | ||
2844 | asihpi->card = card; | ||
2845 | asihpi->pci = hpi_card->pci; | ||
2846 | asihpi->adapter_index = hpi_card->index; | ||
2847 | hpi_handle_error(hpi_adapter_get_info(ss, | ||
2848 | asihpi->adapter_index, | ||
2849 | &asihpi->num_outstreams, | ||
2850 | &asihpi->num_instreams, | ||
2851 | &asihpi->version, | ||
2852 | &asihpi->serial_number, &asihpi->type)); | ||
2853 | |||
2854 | version = asihpi->version; | ||
2855 | snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d " | ||
2856 | "num_instreams=%d S/N=%d\n" | ||
2857 | "hw version %c%d DSP code version %03d\n", | ||
2858 | asihpi->type, asihpi->adapter_index, | ||
2859 | asihpi->num_outstreams, | ||
2860 | asihpi->num_instreams, asihpi->serial_number, | ||
2861 | ((version >> 3) & 0xf) + 'A', | ||
2862 | version & 0x7, | ||
2863 | ((version >> 13) * 100) + ((version >> 7) & 0x3f)); | ||
2864 | |||
2865 | pcm_substreams = asihpi->num_outstreams; | ||
2866 | if (pcm_substreams < asihpi->num_instreams) | ||
2867 | pcm_substreams = asihpi->num_instreams; | ||
2868 | |||
2869 | err = hpi_adapter_get_property(ss, asihpi->adapter_index, | ||
2870 | HPI_ADAPTER_PROPERTY_CAPS1, | ||
2871 | NULL, &asihpi->support_grouping); | ||
2872 | if (err) | ||
2873 | asihpi->support_grouping = 0; | ||
2874 | |||
2875 | err = hpi_adapter_get_property(ss, asihpi->adapter_index, | ||
2876 | HPI_ADAPTER_PROPERTY_CAPS2, | ||
2877 | &asihpi->support_mrx, NULL); | ||
2878 | if (err) | ||
2879 | asihpi->support_mrx = 0; | ||
2880 | |||
2881 | err = hpi_adapter_get_property(ss, asihpi->adapter_index, | ||
2882 | HPI_ADAPTER_PROPERTY_INTERVAL, | ||
2883 | NULL, &asihpi->update_interval_frames); | ||
2884 | if (err) | ||
2885 | asihpi->update_interval_frames = 512; | ||
2886 | |||
2887 | hpi_handle_error(hpi_instream_open(ss, asihpi->adapter_index, | ||
2888 | 0, &h_stream)); | ||
2889 | |||
2890 | err = hpi_instream_host_buffer_free(ss, h_stream); | ||
2891 | asihpi->support_mmap = (!err); | ||
2892 | |||
2893 | hpi_handle_error(hpi_instream_close(ss, h_stream)); | ||
2894 | |||
2895 | err = hpi_adapter_get_property(ss, asihpi->adapter_index, | ||
2896 | HPI_ADAPTER_PROPERTY_CURCHANNELS, | ||
2897 | &asihpi->in_max_chans, &asihpi->out_max_chans); | ||
2898 | if (err) { | ||
2899 | asihpi->in_max_chans = 2; | ||
2900 | asihpi->out_max_chans = 2; | ||
2901 | } | ||
2902 | |||
2903 | snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n", | ||
2904 | asihpi->support_mmap, | ||
2905 | asihpi->support_grouping, | ||
2906 | asihpi->support_mrx | ||
2907 | ); | ||
2908 | |||
2909 | |||
2910 | err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams); | ||
2911 | if (err < 0) { | ||
2912 | snd_printk(KERN_ERR "pcm_new failed\n"); | ||
2913 | goto __nodev; | ||
2914 | } | ||
2915 | err = snd_card_asihpi_mixer_new(asihpi); | ||
2916 | if (err < 0) { | ||
2917 | snd_printk(KERN_ERR "mixer_new failed\n"); | ||
2918 | goto __nodev; | ||
2919 | } | ||
2920 | |||
2921 | err = hpi_mixer_get_control(ss, asihpi->h_mixer, | ||
2922 | HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, | ||
2923 | HPI_CONTROL_SAMPLECLOCK, &h_control); | ||
2924 | |||
2925 | if (!err) | ||
2926 | err = hpi_sample_clock_set_local_rate( | ||
2927 | ss, h_control, adapter_fs); | ||
2928 | |||
2929 | snd_asihpi_proc_init(asihpi); | ||
2930 | |||
2931 | /* always create, can be enabled or disabled dynamically | ||
2932 | by enable_hwdep module param*/ | ||
2933 | snd_asihpi_hpi_new(asihpi, 0, NULL); | ||
2934 | |||
2935 | if (asihpi->support_mmap) | ||
2936 | strcpy(card->driver, "ASIHPI-MMAP"); | ||
2937 | else | ||
2938 | strcpy(card->driver, "ASIHPI"); | ||
2939 | |||
2940 | sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type); | ||
2941 | sprintf(card->longname, "%s %i", | ||
2942 | card->shortname, asihpi->adapter_index); | ||
2943 | err = snd_card_register(card); | ||
2944 | if (!err) { | ||
2945 | hpi_card->snd_card_asihpi = card; | ||
2946 | dev++; | ||
2947 | return 0; | ||
2948 | } | ||
2949 | __nodev: | ||
2950 | snd_card_free(card); | ||
2951 | snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err); | ||
2952 | return err; | ||
2953 | |||
2954 | } | ||
2955 | |||
2956 | static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev) | ||
2957 | { | ||
2958 | struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev); | ||
2959 | |||
2960 | snd_card_free(hpi_card->snd_card_asihpi); | ||
2961 | hpi_card->snd_card_asihpi = NULL; | ||
2962 | asihpi_adapter_remove(pci_dev); | ||
2963 | } | ||
2964 | |||
2965 | static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = { | ||
2966 | {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205, | ||
2967 | HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0, | ||
2968 | (kernel_ulong_t)HPI_6205}, | ||
2969 | {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040, | ||
2970 | HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0, | ||
2971 | (kernel_ulong_t)HPI_6000}, | ||
2972 | {0,} | ||
2973 | }; | ||
2974 | MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl); | ||
2975 | |||
2976 | static struct pci_driver driver = { | ||
2977 | .name = "asihpi", | ||
2978 | .id_table = asihpi_pci_tbl, | ||
2979 | .probe = snd_asihpi_probe, | ||
2980 | .remove = __devexit_p(snd_asihpi_remove), | ||
2981 | #ifdef CONFIG_PM | ||
2982 | /* .suspend = snd_asihpi_suspend, | ||
2983 | .resume = snd_asihpi_resume, */ | ||
2984 | #endif | ||
2985 | }; | ||
2986 | |||
2987 | static int __init snd_asihpi_init(void) | ||
2988 | { | ||
2989 | asihpi_init(); | ||
2990 | return pci_register_driver(&driver); | ||
2991 | } | ||
2992 | |||
2993 | static void __exit snd_asihpi_exit(void) | ||
2994 | { | ||
2995 | |||
2996 | pci_unregister_driver(&driver); | ||
2997 | asihpi_exit(); | ||
2998 | } | ||
2999 | |||
3000 | module_init(snd_asihpi_init) | ||
3001 | module_exit(snd_asihpi_exit) | ||
3002 | |||
diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h new file mode 100644 index 00000000000..99400de6c07 --- /dev/null +++ b/sound/pci/asihpi/hpi.h | |||
@@ -0,0 +1,2001 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | */ | ||
20 | /** \file hpi.h | ||
21 | |||
22 | AudioScience Hardware Programming Interface (HPI) | ||
23 | public API definition. | ||
24 | |||
25 | The HPI is a low-level hardware abstraction layer to all | ||
26 | AudioScience digital audio adapters | ||
27 | */ | ||
28 | /* | ||
29 | You must define one operating system that the HPI is to be compiled under | ||
30 | HPI_OS_WIN32_USER 32bit Windows | ||
31 | HPI_OS_DSP_C6000 DSP TI C6000 (automatically set) | ||
32 | HPI_OS_WDM Windows WDM kernel driver | ||
33 | HPI_OS_LINUX Linux userspace | ||
34 | HPI_OS_LINUX_KERNEL Linux kernel (automatically set) | ||
35 | |||
36 | (C) Copyright AudioScience Inc. 1998-2010 | ||
37 | ******************************************************************************/ | ||
38 | #ifndef _HPI_H_ | ||
39 | #define _HPI_H_ | ||
40 | /* HPI Version | ||
41 | If HPI_VER_MINOR is odd then its a development release not intended for the | ||
42 | public. If HPI_VER_MINOR is even then is a release version | ||
43 | i.e 3.05.02 is a development version | ||
44 | */ | ||
45 | #define HPI_VERSION_CONSTRUCTOR(maj, min, rel) \ | ||
46 | ((maj << 16) + (min << 8) + rel) | ||
47 | |||
48 | #define HPI_VER_MAJOR(v) ((int)(v >> 16)) | ||
49 | #define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF)) | ||
50 | #define HPI_VER_RELEASE(v) ((int)(v & 0xFF)) | ||
51 | |||
52 | /* Use single digits for versions less that 10 to avoid octal. */ | ||
53 | #define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 18) | ||
54 | |||
55 | /* Library version as documented in hpi-api-versions.txt */ | ||
56 | #define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0) | ||
57 | |||
58 | #include <linux/types.h> | ||
59 | #define HPI_EXCLUDE_DEPRECATED | ||
60 | |||
61 | /******************************************************************************/ | ||
62 | /******************************************************************************/ | ||
63 | /******** HPI API DEFINITIONS *****/ | ||
64 | /******************************************************************************/ | ||
65 | /******************************************************************************/ | ||
66 | /*******************************************/ | ||
67 | /** Audio format types | ||
68 | \ingroup stream | ||
69 | */ | ||
70 | enum HPI_FORMATS { | ||
71 | /** Used internally on adapter. */ | ||
72 | HPI_FORMAT_MIXER_NATIVE = 0, | ||
73 | /** 8-bit unsigned PCM. Windows equivalent is WAVE_FORMAT_PCM. */ | ||
74 | HPI_FORMAT_PCM8_UNSIGNED = 1, | ||
75 | /** 16-bit signed PCM. Windows equivalent is WAVE_FORMAT_PCM. */ | ||
76 | HPI_FORMAT_PCM16_SIGNED = 2, | ||
77 | /** MPEG-1 Layer-1. */ | ||
78 | HPI_FORMAT_MPEG_L1 = 3, | ||
79 | /** MPEG-1 Layer-2. | ||
80 | |||
81 | Windows equivalent is WAVE_FORMAT_MPEG. | ||
82 | |||
83 | The following table shows what combinations of mode and bitrate are possible: | ||
84 | |||
85 | <table border=1 cellspacing=0 cellpadding=5> | ||
86 | <tr> | ||
87 | <td><p><b>Bitrate (kbs)</b></p> | ||
88 | <td><p><b>Mono</b></p> | ||
89 | <td><p><b>Stereo,<br>Joint Stereo or<br>Dual Channel</b></p> | ||
90 | |||
91 | <tr><td>32<td>X<td>_ | ||
92 | <tr><td>40<td>_<td>_ | ||
93 | <tr><td>48<td>X<td>_ | ||
94 | <tr><td>56<td>X<td>_ | ||
95 | <tr><td>64<td>X<td>X | ||
96 | <tr><td>80<td>X<td>_ | ||
97 | <tr><td>96<td>X<td>X | ||
98 | <tr><td>112<td>X<td>X | ||
99 | <tr><td>128<td>X<td>X | ||
100 | <tr><td>160<td>X<td>X | ||
101 | <tr><td>192<td>X<td>X | ||
102 | <tr><td>224<td>_<td>X | ||
103 | <tr><td>256<td>-<td>X | ||
104 | <tr><td>320<td>-<td>X | ||
105 | <tr><td>384<td>_<td>X | ||
106 | </table> | ||
107 | */ | ||
108 | HPI_FORMAT_MPEG_L2 = 4, | ||
109 | /** MPEG-1 Layer-3. | ||
110 | Windows equivalent is WAVE_FORMAT_MPEG. | ||
111 | |||
112 | The following table shows what combinations of mode and bitrate are possible: | ||
113 | |||
114 | <table border=1 cellspacing=0 cellpadding=5> | ||
115 | <tr> | ||
116 | <td><p><b>Bitrate (kbs)</b></p> | ||
117 | <td><p><b>Mono<br>Stereo @ 8,<br>11.025 and<br>12kHz*</b></p> | ||
118 | <td><p><b>Mono<br>Stereo @ 16,<br>22.050 and<br>24kHz*</b></p> | ||
119 | <td><p><b>Mono<br>Stereo @ 32,<br>44.1 and<br>48kHz</b></p> | ||
120 | |||
121 | <tr><td>16<td>X<td>X<td>_ | ||
122 | <tr><td>24<td>X<td>X<td>_ | ||
123 | <tr><td>32<td>X<td>X<td>X | ||
124 | <tr><td>40<td>X<td>X<td>X | ||
125 | <tr><td>48<td>X<td>X<td>X | ||
126 | <tr><td>56<td>X<td>X<td>X | ||
127 | <tr><td>64<td>X<td>X<td>X | ||
128 | <tr><td>80<td>_<td>X<td>X | ||
129 | <tr><td>96<td>_<td>X<td>X | ||
130 | <tr><td>112<td>_<td>X<td>X | ||
131 | <tr><td>128<td>_<td>X<td>X | ||
132 | <tr><td>144<td>_<td>X<td>_ | ||
133 | <tr><td>160<td>_<td>X<td>X | ||
134 | <tr><td>192<td>_<td>_<td>X | ||
135 | <tr><td>224<td>_<td>_<td>X | ||
136 | <tr><td>256<td>-<td>_<td>X | ||
137 | <tr><td>320<td>-<td>_<td>X | ||
138 | </table> | ||
139 | \b * Available on the ASI6000 series only | ||
140 | */ | ||
141 | HPI_FORMAT_MPEG_L3 = 5, | ||
142 | /** Dolby AC-2. */ | ||
143 | HPI_FORMAT_DOLBY_AC2 = 6, | ||
144 | /** Dolbt AC-3. */ | ||
145 | HPI_FORMAT_DOLBY_AC3 = 7, | ||
146 | /** 16-bit PCM big-endian. */ | ||
147 | HPI_FORMAT_PCM16_BIGENDIAN = 8, | ||
148 | /** TAGIT-1 algorithm - hits. */ | ||
149 | HPI_FORMAT_AA_TAGIT1_HITS = 9, | ||
150 | /** TAGIT-1 algorithm - inserts. */ | ||
151 | HPI_FORMAT_AA_TAGIT1_INSERTS = 10, | ||
152 | /** 32-bit signed PCM. Windows equivalent is WAVE_FORMAT_PCM. | ||
153 | Each sample is a 32bit word. The most significant 24 bits contain a 24-bit | ||
154 | sample and the least significant 8 bits are set to 0. | ||
155 | */ | ||
156 | HPI_FORMAT_PCM32_SIGNED = 11, | ||
157 | /** Raw bitstream - unknown format. */ | ||
158 | HPI_FORMAT_RAW_BITSTREAM = 12, | ||
159 | /** TAGIT-1 algorithm hits - extended. */ | ||
160 | HPI_FORMAT_AA_TAGIT1_HITS_EX1 = 13, | ||
161 | /** 32-bit PCM as an IEEE float. Windows equivalent is WAVE_FORMAT_IEEE_FLOAT. | ||
162 | Each sample is a 32bit word in IEEE754 floating point format. | ||
163 | The range is +1.0 to -1.0, which corresponds to digital fullscale. | ||
164 | */ | ||
165 | HPI_FORMAT_PCM32_FLOAT = 14, | ||
166 | /** 24-bit PCM signed. Windows equivalent is WAVE_FORMAT_PCM. */ | ||
167 | HPI_FORMAT_PCM24_SIGNED = 15, | ||
168 | /** OEM format 1 - private. */ | ||
169 | HPI_FORMAT_OEM1 = 16, | ||
170 | /** OEM format 2 - private. */ | ||
171 | HPI_FORMAT_OEM2 = 17, | ||
172 | /** Undefined format. */ | ||
173 | HPI_FORMAT_UNDEFINED = 0xffff | ||
174 | }; | ||
175 | |||
176 | /******************************************* in/out Stream states */ | ||
177 | /*******************************************/ | ||
178 | /** Stream States | ||
179 | \ingroup stream | ||
180 | */ | ||
181 | enum HPI_STREAM_STATES { | ||
182 | /** State stopped - stream is stopped. */ | ||
183 | HPI_STATE_STOPPED = 1, | ||
184 | /** State playing - stream is playing audio. */ | ||
185 | HPI_STATE_PLAYING = 2, | ||
186 | /** State recording - stream is recording. */ | ||
187 | HPI_STATE_RECORDING = 3, | ||
188 | /** State drained - playing stream ran out of data to play. */ | ||
189 | HPI_STATE_DRAINED = 4, | ||
190 | /** State generate sine - to be implemented. */ | ||
191 | HPI_STATE_SINEGEN = 5, | ||
192 | /** State wait - used for inter-card sync to mean waiting for all | ||
193 | cards to be ready. */ | ||
194 | HPI_STATE_WAIT = 6 | ||
195 | }; | ||
196 | /******************************************* mixer source node types */ | ||
197 | /** Source node types | ||
198 | \ingroup mixer | ||
199 | */ | ||
200 | enum HPI_SOURCENODES { | ||
201 | /** This define can be used instead of 0 to indicate | ||
202 | that there is no valid source node. A control that | ||
203 | exists on a destination node can be searched for using a source | ||
204 | node value of either 0, or HPI_SOURCENODE_NONE */ | ||
205 | HPI_SOURCENODE_NONE = 100, | ||
206 | /** \deprecated Use HPI_SOURCENODE_NONE instead. */ | ||
207 | HPI_SOURCENODE_BASE = 100, | ||
208 | /** Out Stream (Play) node. */ | ||
209 | HPI_SOURCENODE_OSTREAM = 101, | ||
210 | /** Line in node - could be analog, AES/EBU or network. */ | ||
211 | HPI_SOURCENODE_LINEIN = 102, | ||
212 | HPI_SOURCENODE_AESEBU_IN = 103, /**< AES/EBU input node. */ | ||
213 | HPI_SOURCENODE_TUNER = 104, /**< tuner node. */ | ||
214 | HPI_SOURCENODE_RF = 105, /**< RF input node. */ | ||
215 | HPI_SOURCENODE_CLOCK_SOURCE = 106, /**< clock source node. */ | ||
216 | HPI_SOURCENODE_RAW_BITSTREAM = 107, /**< raw bitstream node. */ | ||
217 | HPI_SOURCENODE_MICROPHONE = 108, /**< microphone node. */ | ||
218 | /** Cobranet input node - | ||
219 | Audio samples come from the Cobranet network and into the device. */ | ||
220 | HPI_SOURCENODE_COBRANET = 109, | ||
221 | HPI_SOURCENODE_ANALOG = 110, /**< analog input node. */ | ||
222 | HPI_SOURCENODE_ADAPTER = 111, /**< adapter node. */ | ||
223 | /* !!!Update this AND hpidebug.h if you add a new sourcenode type!!! */ | ||
224 | HPI_SOURCENODE_LAST_INDEX = 111 /**< largest ID */ | ||
225 | /* AX6 max sourcenode types = 15 */ | ||
226 | }; | ||
227 | |||
228 | /******************************************* mixer dest node types */ | ||
229 | /** Destination node types | ||
230 | \ingroup mixer | ||
231 | */ | ||
232 | enum HPI_DESTNODES { | ||
233 | /** This define can be used instead of 0 to indicate | ||
234 | that there is no valid destination node. A control that | ||
235 | exists on a source node can be searched for using a destination | ||
236 | node value of either 0, or HPI_DESTNODE_NONE */ | ||
237 | HPI_DESTNODE_NONE = 200, | ||
238 | /** \deprecated Use HPI_DESTNODE_NONE instead. */ | ||
239 | HPI_DESTNODE_BASE = 200, | ||
240 | /** In Stream (Record) node. */ | ||
241 | HPI_DESTNODE_ISTREAM = 201, | ||
242 | HPI_DESTNODE_LINEOUT = 202, /**< line out node. */ | ||
243 | HPI_DESTNODE_AESEBU_OUT = 203, /**< AES/EBU output node. */ | ||
244 | HPI_DESTNODE_RF = 204, /**< RF output node. */ | ||
245 | HPI_DESTNODE_SPEAKER = 205, /**< speaker output node. */ | ||
246 | /** Cobranet output node - | ||
247 | Audio samples from the device are sent out on the Cobranet network.*/ | ||
248 | HPI_DESTNODE_COBRANET = 206, | ||
249 | HPI_DESTNODE_ANALOG = 207, /**< analog output node. */ | ||
250 | |||
251 | /* !!!Update this AND hpidebug.h if you add a new destnode type!!! */ | ||
252 | HPI_DESTNODE_LAST_INDEX = 207 /**< largest ID */ | ||
253 | /* AX6 max destnode types = 15 */ | ||
254 | }; | ||
255 | |||
256 | /*******************************************/ | ||
257 | /** Mixer control types | ||
258 | \ingroup mixer | ||
259 | */ | ||
260 | enum HPI_CONTROLS { | ||
261 | HPI_CONTROL_GENERIC = 0, /**< generic control. */ | ||
262 | HPI_CONTROL_CONNECTION = 1, /**< A connection between nodes. */ | ||
263 | HPI_CONTROL_VOLUME = 2, /**< volume control - works in dB_fs. */ | ||
264 | HPI_CONTROL_METER = 3, /**< peak meter control. */ | ||
265 | HPI_CONTROL_MUTE = 4, /*mute control - not used at present. */ | ||
266 | HPI_CONTROL_MULTIPLEXER = 5, /**< multiplexer control. */ | ||
267 | |||
268 | HPI_CONTROL_AESEBU_TRANSMITTER = 6, /**< AES/EBU transmitter control. */ | ||
269 | HPI_CONTROL_AESEBUTX = HPI_CONTROL_AESEBU_TRANSMITTER, | ||
270 | |||
271 | HPI_CONTROL_AESEBU_RECEIVER = 7, /**< AES/EBU receiver control. */ | ||
272 | HPI_CONTROL_AESEBURX = HPI_CONTROL_AESEBU_RECEIVER, | ||
273 | |||
274 | HPI_CONTROL_LEVEL = 8, /**< level/trim control - works in d_bu. */ | ||
275 | HPI_CONTROL_TUNER = 9, /**< tuner control. */ | ||
276 | /* HPI_CONTROL_ONOFFSWITCH = 10 */ | ||
277 | HPI_CONTROL_VOX = 11, /**< vox control. */ | ||
278 | /* HPI_CONTROL_AES18_TRANSMITTER = 12 */ | ||
279 | /* HPI_CONTROL_AES18_RECEIVER = 13 */ | ||
280 | /* HPI_CONTROL_AES18_BLOCKGENERATOR = 14 */ | ||
281 | HPI_CONTROL_CHANNEL_MODE = 15, /**< channel mode control. */ | ||
282 | |||
283 | HPI_CONTROL_BITSTREAM = 16, /**< bitstream control. */ | ||
284 | HPI_CONTROL_SAMPLECLOCK = 17, /**< sample clock control. */ | ||
285 | HPI_CONTROL_MICROPHONE = 18, /**< microphone control. */ | ||
286 | HPI_CONTROL_PARAMETRIC_EQ = 19, /**< parametric EQ control. */ | ||
287 | HPI_CONTROL_EQUALIZER = HPI_CONTROL_PARAMETRIC_EQ, | ||
288 | |||
289 | HPI_CONTROL_COMPANDER = 20, /**< compander control. */ | ||
290 | HPI_CONTROL_COBRANET = 21, /**< cobranet control. */ | ||
291 | HPI_CONTROL_TONEDETECTOR = 22, /**< tone detector control. */ | ||
292 | HPI_CONTROL_SILENCEDETECTOR = 23, /**< silence detector control. */ | ||
293 | HPI_CONTROL_PAD = 24, /**< tuner PAD control. */ | ||
294 | HPI_CONTROL_SRC = 25, /**< samplerate converter control. */ | ||
295 | HPI_CONTROL_UNIVERSAL = 26, /**< universal control. */ | ||
296 | |||
297 | /* !!! Update this AND hpidebug.h if you add a new control type!!!*/ | ||
298 | HPI_CONTROL_LAST_INDEX = 26 /**<highest control type ID */ | ||
299 | /* WARNING types 256 or greater impact bit packing in all AX6 DSP code */ | ||
300 | }; | ||
301 | |||
302 | /* Shorthand names that match attribute names */ | ||
303 | |||
304 | /******************************************* ADAPTER ATTRIBUTES ****/ | ||
305 | |||
306 | /** Adapter properties | ||
307 | These are used in HPI_AdapterSetProperty() and HPI_AdapterGetProperty() | ||
308 | \ingroup adapter | ||
309 | */ | ||
310 | enum HPI_ADAPTER_PROPERTIES { | ||
311 | /** \internal Used in dwProperty field of HPI_AdapterSetProperty() and | ||
312 | HPI_AdapterGetProperty(). This errata applies to all ASI6000 cards with both | ||
313 | analog and digital outputs. The CS4224 A/D+D/A has a one sample delay between | ||
314 | left and right channels on both its input (ADC) and output (DAC). | ||
315 | More details are available in Cirrus Logic errata ER284B2. | ||
316 | PDF available from www.cirrus.com, released by Cirrus in 2001. | ||
317 | */ | ||
318 | HPI_ADAPTER_PROPERTY_ERRATA_1 = 1, | ||
319 | |||
320 | /** Adapter grouping property | ||
321 | Indicates whether the adapter supports the grouping API (for ASIO and SSX2) | ||
322 | */ | ||
323 | HPI_ADAPTER_PROPERTY_GROUPING = 2, | ||
324 | |||
325 | /** Driver SSX2 property | ||
326 | Tells the kernel driver to turn on SSX2 stream mapping. | ||
327 | This feature is not used by the DSP. In fact the call is completely processed | ||
328 | by the driver and is not passed on to the DSP at all. | ||
329 | */ | ||
330 | HPI_ADAPTER_PROPERTY_ENABLE_SSX2 = 3, | ||
331 | |||
332 | /** Adapter SSX2 property | ||
333 | Indicates the state of the adapter's SSX2 setting. This setting is stored in | ||
334 | non-volatile memory on the adapter. A typical call sequence would be to use | ||
335 | HPI_ADAPTER_PROPERTY_SSX2_SETTING to set SSX2 on the adapter and then to reload | ||
336 | the driver. The driver would query HPI_ADAPTER_PROPERTY_SSX2_SETTING during startup | ||
337 | and if SSX2 is set, it would then call HPI_ADAPTER_PROPERTY_ENABLE_SSX2 to enable | ||
338 | SSX2 stream mapping within the kernel level of the driver. | ||
339 | */ | ||
340 | HPI_ADAPTER_PROPERTY_SSX2_SETTING = 4, | ||
341 | |||
342 | /** Base number for readonly properties */ | ||
343 | HPI_ADAPTER_PROPERTY_READONLYBASE = 256, | ||
344 | |||
345 | /** Readonly adapter latency property. | ||
346 | This property returns in the input and output latency in samples. | ||
347 | Property 1 is the estimated input latency | ||
348 | in samples, while Property 2 is that output latency in samples. | ||
349 | */ | ||
350 | HPI_ADAPTER_PROPERTY_LATENCY = 256, | ||
351 | |||
352 | /** Readonly adapter granularity property. | ||
353 | The granulariy is the smallest size chunk of stereo samples that is processed by | ||
354 | the adapter. | ||
355 | This property returns the record granularity in samples in Property 1. | ||
356 | Property 2 returns the play granularity. | ||
357 | */ | ||
358 | HPI_ADAPTER_PROPERTY_GRANULARITY = 257, | ||
359 | |||
360 | /** Readonly adapter number of current channels property. | ||
361 | Property 1 is the number of record channels per record device. | ||
362 | Property 2 is the number of play channels per playback device.*/ | ||
363 | HPI_ADAPTER_PROPERTY_CURCHANNELS = 258, | ||
364 | |||
365 | /** Readonly adapter software version. | ||
366 | The SOFTWARE_VERSION property returns the version of the software running | ||
367 | on the adapter as Major.Minor.Release. | ||
368 | Property 1 contains Major in bits 15..8 and Minor in bits 7..0. | ||
369 | Property 2 contains Release in bits 7..0. */ | ||
370 | HPI_ADAPTER_PROPERTY_SOFTWARE_VERSION = 259, | ||
371 | |||
372 | /** Readonly adapter MAC address MSBs. | ||
373 | The MAC_ADDRESS_MSB property returns | ||
374 | the most significant 32 bits of the MAC address. | ||
375 | Property 1 contains bits 47..32 of the MAC address. | ||
376 | Property 2 contains bits 31..16 of the MAC address. */ | ||
377 | HPI_ADAPTER_PROPERTY_MAC_ADDRESS_MSB = 260, | ||
378 | |||
379 | /** Readonly adapter MAC address LSBs | ||
380 | The MAC_ADDRESS_LSB property returns | ||
381 | the least significant 16 bits of the MAC address. | ||
382 | Property 1 contains bits 15..0 of the MAC address. */ | ||
383 | HPI_ADAPTER_PROPERTY_MAC_ADDRESS_LSB = 261, | ||
384 | |||
385 | /** Readonly extended adapter type number | ||
386 | The EXTENDED_ADAPTER_TYPE property returns the 4 digits of an extended | ||
387 | adapter type, i.e ASI8920-0022, 0022 is the extended type. | ||
388 | The digits are returned as ASCII characters rather than the hex digits that | ||
389 | are returned for the main type | ||
390 | Property 1 returns the 1st two (left most) digits, i.e "00" | ||
391 | in the example above, the upper byte being the left most digit. | ||
392 | Property 2 returns the 2nd two digits, i.e "22" in the example above*/ | ||
393 | HPI_ADAPTER_PROPERTY_EXTENDED_ADAPTER_TYPE = 262, | ||
394 | |||
395 | /** Readonly debug log buffer information */ | ||
396 | HPI_ADAPTER_PROPERTY_LOGTABLEN = 263, | ||
397 | HPI_ADAPTER_PROPERTY_LOGTABBEG = 264, | ||
398 | |||
399 | /** Readonly adapter IP address | ||
400 | For 192.168.1.101 | ||
401 | Property 1 returns the 1st two (left most) digits, i.e 192*256 + 168 | ||
402 | in the example above, the upper byte being the left most digit. | ||
403 | Property 2 returns the 2nd two digits, i.e 1*256 + 101 in the example above, */ | ||
404 | HPI_ADAPTER_PROPERTY_IP_ADDRESS = 265, | ||
405 | |||
406 | /** Readonly adapter buffer processed count. Returns a buffer processed count | ||
407 | that is incremented every time all buffers for all streams are updated. This | ||
408 | is useful for checking completion of all stream operations across the adapter | ||
409 | when using grouped streams. | ||
410 | */ | ||
411 | HPI_ADAPTER_PROPERTY_BUFFER_UPDATE_COUNT = 266, | ||
412 | |||
413 | /** Readonly mixer and stream intervals | ||
414 | |||
415 | These intervals are measured in mixer frames. | ||
416 | To convert to time, divide by the adapter samplerate. | ||
417 | |||
418 | The mixer interval is the number of frames processed in one mixer iteration. | ||
419 | The stream update interval is the interval at which streams check for and | ||
420 | process data, and BBM host buffer counters are updated. | ||
421 | |||
422 | Property 1 is the mixer interval in mixer frames. | ||
423 | Property 2 is the stream update interval in mixer frames. | ||
424 | */ | ||
425 | HPI_ADAPTER_PROPERTY_INTERVAL = 267, | ||
426 | /** Adapter capabilities 1 | ||
427 | Property 1 - adapter can do multichannel (SSX1) | ||
428 | Property 2 - adapter can do stream grouping (supports SSX2) | ||
429 | */ | ||
430 | HPI_ADAPTER_PROPERTY_CAPS1 = 268, | ||
431 | /** Adapter capabilities 2 | ||
432 | Property 1 - adapter can do samplerate conversion (MRX) | ||
433 | Property 2 - adapter can do timestretch (TSX) | ||
434 | */ | ||
435 | HPI_ADAPTER_PROPERTY_CAPS2 = 269 | ||
436 | }; | ||
437 | |||
438 | /** Adapter mode commands | ||
439 | |||
440 | Used in wQueryOrSet field of HPI_AdapterSetModeEx(). | ||
441 | \ingroup adapter | ||
442 | */ | ||
443 | enum HPI_ADAPTER_MODE_CMDS { | ||
444 | HPI_ADAPTER_MODE_SET = 0, | ||
445 | HPI_ADAPTER_MODE_QUERY = 1 | ||
446 | }; | ||
447 | |||
448 | /** Adapter Modes | ||
449 | These are used by HPI_AdapterSetModeEx() | ||
450 | |||
451 | \warning - more than 16 possible modes breaks | ||
452 | a bitmask in the Windows WAVE DLL | ||
453 | \ingroup adapter | ||
454 | */ | ||
455 | enum HPI_ADAPTER_MODES { | ||
456 | /** 4 outstream mode. | ||
457 | - ASI6114: 1 instream | ||
458 | - ASI6044: 4 instreams | ||
459 | - ASI6012: 1 instream | ||
460 | - ASI6102: no instreams | ||
461 | - ASI6022, ASI6122: 2 instreams | ||
462 | - ASI5111, ASI5101: 2 instreams | ||
463 | - ASI652x, ASI662x: 2 instreams | ||
464 | - ASI654x, ASI664x: 4 instreams | ||
465 | */ | ||
466 | HPI_ADAPTER_MODE_4OSTREAM = 1, | ||
467 | |||
468 | /** 6 outstream mode. | ||
469 | - ASI6012: 1 instream, | ||
470 | - ASI6022, ASI6122: 2 instreams | ||
471 | - ASI652x, ASI662x: 4 instreams | ||
472 | */ | ||
473 | HPI_ADAPTER_MODE_6OSTREAM = 2, | ||
474 | |||
475 | /** 8 outstream mode. | ||
476 | - ASI6114: 8 instreams | ||
477 | - ASI6118: 8 instreams | ||
478 | - ASI6585: 8 instreams | ||
479 | */ | ||
480 | HPI_ADAPTER_MODE_8OSTREAM = 3, | ||
481 | |||
482 | /** 16 outstream mode. | ||
483 | - ASI6416 16 instreams | ||
484 | - ASI6518, ASI6618 16 instreams | ||
485 | - ASI6118 16 mono out and in streams | ||
486 | */ | ||
487 | HPI_ADAPTER_MODE_16OSTREAM = 4, | ||
488 | |||
489 | /** one outstream mode. | ||
490 | - ASI5111 1 outstream, 1 instream | ||
491 | */ | ||
492 | HPI_ADAPTER_MODE_1OSTREAM = 5, | ||
493 | |||
494 | /** ASI504X mode 1. 12 outstream, 4 instream 0 to 48kHz sample rates | ||
495 | (see ASI504X datasheet for more info). | ||
496 | */ | ||
497 | HPI_ADAPTER_MODE_1 = 6, | ||
498 | |||
499 | /** ASI504X mode 2. 4 outstreams, 4 instreams at 0 to 192kHz sample rates | ||
500 | (see ASI504X datasheet for more info). | ||
501 | */ | ||
502 | HPI_ADAPTER_MODE_2 = 7, | ||
503 | |||
504 | /** ASI504X mode 3. 4 outstreams, 4 instreams at 0 to 192kHz sample rates | ||
505 | (see ASI504X datasheet for more info). | ||
506 | */ | ||
507 | HPI_ADAPTER_MODE_3 = 8, | ||
508 | |||
509 | /** ASI504X multichannel mode. | ||
510 | 2 outstreams -> 4 line outs = 1 to 8 channel streams), | ||
511 | 4 lineins -> 1 instream (1 to 8 channel streams) at 0-48kHz. | ||
512 | For more info see the SSX Specification. | ||
513 | */ | ||
514 | HPI_ADAPTER_MODE_MULTICHANNEL = 9, | ||
515 | |||
516 | /** 12 outstream mode. | ||
517 | - ASI6514, ASI6614: 2 instreams | ||
518 | - ASI6540,ASI6544: 8 instreams | ||
519 | - ASI6640,ASI6644: 8 instreams | ||
520 | */ | ||
521 | HPI_ADAPTER_MODE_12OSTREAM = 10, | ||
522 | |||
523 | /** 9 outstream mode. | ||
524 | - ASI6044: 8 instreams | ||
525 | */ | ||
526 | HPI_ADAPTER_MODE_9OSTREAM = 11, | ||
527 | |||
528 | /** mono mode. | ||
529 | - ASI6416: 16 outstreams/instreams | ||
530 | - ASI5402: 2 outstreams/instreams | ||
531 | */ | ||
532 | HPI_ADAPTER_MODE_MONO = 12, | ||
533 | |||
534 | /** Low latency mode. | ||
535 | - ASI6416/ASI6316: 1 16 channel outstream and instream | ||
536 | */ | ||
537 | HPI_ADAPTER_MODE_LOW_LATENCY = 13 | ||
538 | }; | ||
539 | |||
540 | /* Note, adapters can have more than one capability - | ||
541 | encoding as bitfield is recommended. */ | ||
542 | #define HPI_CAPABILITY_NONE (0) | ||
543 | #define HPI_CAPABILITY_MPEG_LAYER3 (1) | ||
544 | |||
545 | /* Set this equal to maximum capability index, | ||
546 | Must not be greater than 32 - see axnvdef.h */ | ||
547 | #define HPI_CAPABILITY_MAX 1 | ||
548 | /* #define HPI_CAPABILITY_AAC 2 */ | ||
549 | |||
550 | /******************************************* STREAM ATTRIBUTES ****/ | ||
551 | |||
552 | /** MPEG Ancillary Data modes | ||
553 | |||
554 | The mode for the ancillary data insertion or extraction to operate in. | ||
555 | \ingroup stream | ||
556 | */ | ||
557 | enum HPI_MPEG_ANC_MODES { | ||
558 | /** the MPEG frames have energy information stored in them (5 bytes per stereo frame, 3 per mono) */ | ||
559 | HPI_MPEG_ANC_HASENERGY = 0, | ||
560 | /** the entire ancillary data field is taken up by data from the Anc data buffer | ||
561 | On encode, the encoder will insert the energy bytes before filling the remainder | ||
562 | of the ancillary data space with data from the ancillary data buffer. | ||
563 | */ | ||
564 | HPI_MPEG_ANC_RAW = 1 | ||
565 | }; | ||
566 | |||
567 | /** Ancillary Data Alignment | ||
568 | \ingroup instream | ||
569 | */ | ||
570 | enum HPI_ISTREAM_MPEG_ANC_ALIGNS { | ||
571 | /** data is packed against the end of data, then padded to the end of frame */ | ||
572 | HPI_MPEG_ANC_ALIGN_LEFT = 0, | ||
573 | /** data is packed against the end of the frame */ | ||
574 | HPI_MPEG_ANC_ALIGN_RIGHT = 1 | ||
575 | }; | ||
576 | |||
577 | /** MPEG modes | ||
578 | MPEG modes - can be used optionally for HPI_FormatCreate() | ||
579 | parameter dwAttributes. | ||
580 | |||
581 | Using any mode setting other than HPI_MPEG_MODE_DEFAULT | ||
582 | with single channel format will return an error. | ||
583 | \ingroup stream | ||
584 | */ | ||
585 | enum HPI_MPEG_MODES { | ||
586 | /** Causes the MPEG-1 Layer II bitstream to be recorded | ||
587 | in single_channel mode when the number of channels is 1 and in stereo when the | ||
588 | number of channels is 2. */ | ||
589 | HPI_MPEG_MODE_DEFAULT = 0, | ||
590 | /** Standard stereo without joint-stereo compression */ | ||
591 | HPI_MPEG_MODE_STEREO = 1, | ||
592 | /** Joint stereo */ | ||
593 | HPI_MPEG_MODE_JOINTSTEREO = 2, | ||
594 | /** Left and Right channels are completely independent */ | ||
595 | HPI_MPEG_MODE_DUALCHANNEL = 3 | ||
596 | }; | ||
597 | /******************************************* MIXER ATTRIBUTES ****/ | ||
598 | |||
599 | /* \defgroup mixer_flags Mixer flags for HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES | ||
600 | { | ||
601 | */ | ||
602 | #define HPI_MIXER_GET_CONTROL_MULTIPLE_CHANGED (0) | ||
603 | #define HPI_MIXER_GET_CONTROL_MULTIPLE_RESET (1) | ||
604 | /*}*/ | ||
605 | |||
606 | /** Commands used by HPI_MixerStore() | ||
607 | \ingroup mixer | ||
608 | */ | ||
609 | enum HPI_MIXER_STORE_COMMAND { | ||
610 | /** Save all mixer control settings. */ | ||
611 | HPI_MIXER_STORE_SAVE = 1, | ||
612 | /** Restore all controls from saved. */ | ||
613 | HPI_MIXER_STORE_RESTORE = 2, | ||
614 | /** Delete saved control settings. */ | ||
615 | HPI_MIXER_STORE_DELETE = 3, | ||
616 | /** Enable auto storage of some control settings. */ | ||
617 | HPI_MIXER_STORE_ENABLE = 4, | ||
618 | /** Disable auto storage of some control settings. */ | ||
619 | HPI_MIXER_STORE_DISABLE = 5, | ||
620 | /** Save the attributes of a single control. */ | ||
621 | HPI_MIXER_STORE_SAVE_SINGLE = 6 | ||
622 | }; | ||
623 | |||
624 | /************************************* CONTROL ATTRIBUTE VALUES ****/ | ||
625 | /** Used by mixer plugin enable functions | ||
626 | |||
627 | E.g. HPI_ParametricEQ_SetState() | ||
628 | \ingroup mixer | ||
629 | */ | ||
630 | enum HPI_SWITCH_STATES { | ||
631 | HPI_SWITCH_OFF = 0, /**< turn the mixer plugin on. */ | ||
632 | HPI_SWITCH_ON = 1 /**< turn the mixer plugin off. */ | ||
633 | }; | ||
634 | |||
635 | /* Volume control special gain values */ | ||
636 | /** volumes units are 100ths of a dB | ||
637 | \ingroup volume | ||
638 | */ | ||
639 | #define HPI_UNITS_PER_dB 100 | ||
640 | /** turns volume control OFF or MUTE | ||
641 | \ingroup volume | ||
642 | */ | ||
643 | #define HPI_GAIN_OFF (-100 * HPI_UNITS_PER_dB) | ||
644 | |||
645 | /** value returned for no signal | ||
646 | \ingroup meter | ||
647 | */ | ||
648 | #define HPI_METER_MINIMUM (-150 * HPI_UNITS_PER_dB) | ||
649 | |||
650 | /** autofade profiles | ||
651 | \ingroup volume | ||
652 | */ | ||
653 | enum HPI_VOLUME_AUTOFADES { | ||
654 | /** log fade - dB attenuation changes linearly over time */ | ||
655 | HPI_VOLUME_AUTOFADE_LOG = 2, | ||
656 | /** linear fade - amplitude changes linearly */ | ||
657 | HPI_VOLUME_AUTOFADE_LINEAR = 3 | ||
658 | }; | ||
659 | |||
660 | /** The physical encoding format of the AESEBU I/O. | ||
661 | |||
662 | Used in HPI_AESEBU_Transmitter_SetFormat(), HPI_AESEBU_Receiver_SetFormat() | ||
663 | along with related Get and Query functions | ||
664 | \ingroup aestx | ||
665 | */ | ||
666 | enum HPI_AESEBU_FORMATS { | ||
667 | /** AES/EBU physical format - AES/EBU balanced "professional" */ | ||
668 | HPI_AESEBU_FORMAT_AESEBU = 1, | ||
669 | /** AES/EBU physical format - S/PDIF unbalanced "consumer" */ | ||
670 | HPI_AESEBU_FORMAT_SPDIF = 2 | ||
671 | }; | ||
672 | |||
673 | /** AES/EBU error status bits | ||
674 | |||
675 | Returned by HPI_AESEBU_Receiver_GetErrorStatus() | ||
676 | \ingroup aesrx | ||
677 | */ | ||
678 | enum HPI_AESEBU_ERRORS { | ||
679 | /** bit0: 1 when PLL is not locked */ | ||
680 | HPI_AESEBU_ERROR_NOT_LOCKED = 0x01, | ||
681 | /** bit1: 1 when signal quality is poor */ | ||
682 | HPI_AESEBU_ERROR_POOR_QUALITY = 0x02, | ||
683 | /** bit2: 1 when there is a parity error */ | ||
684 | HPI_AESEBU_ERROR_PARITY_ERROR = 0x04, | ||
685 | /** bit3: 1 when there is a bi-phase coding violation */ | ||
686 | HPI_AESEBU_ERROR_BIPHASE_VIOLATION = 0x08, | ||
687 | /** bit4: 1 when the validity bit is high */ | ||
688 | HPI_AESEBU_ERROR_VALIDITY = 0x10, | ||
689 | /** bit5: 1 when the CRC error bit is high */ | ||
690 | HPI_AESEBU_ERROR_CRC = 0x20 | ||
691 | }; | ||
692 | |||
693 | /** \addtogroup pad | ||
694 | \{ | ||
695 | */ | ||
696 | /** The text string containing the station/channel combination. */ | ||
697 | #define HPI_PAD_CHANNEL_NAME_LEN 16 | ||
698 | /** The text string containing the artist. */ | ||
699 | #define HPI_PAD_ARTIST_LEN 64 | ||
700 | /** The text string containing the title. */ | ||
701 | #define HPI_PAD_TITLE_LEN 64 | ||
702 | /** The text string containing the comment. */ | ||
703 | #define HPI_PAD_COMMENT_LEN 256 | ||
704 | /** The PTY when the tuner has not recieved any PTY. */ | ||
705 | #define HPI_PAD_PROGRAM_TYPE_INVALID 0xffff | ||
706 | /** \} */ | ||
707 | |||
708 | /** Data types for PTY string translation. | ||
709 | \ingroup rds | ||
710 | */ | ||
711 | enum eHPI_RDS_type { | ||
712 | HPI_RDS_DATATYPE_RDS = 0, /**< RDS bitstream.*/ | ||
713 | HPI_RDS_DATATYPE_RBDS = 1 /**< RBDS bitstream.*/ | ||
714 | }; | ||
715 | |||
716 | /** Tuner bands | ||
717 | |||
718 | Used for HPI_Tuner_SetBand(),HPI_Tuner_GetBand() | ||
719 | \ingroup tuner | ||
720 | */ | ||
721 | enum HPI_TUNER_BAND { | ||
722 | HPI_TUNER_BAND_AM = 1, /**< AM band */ | ||
723 | HPI_TUNER_BAND_FM = 2, /**< FM band (mono) */ | ||
724 | HPI_TUNER_BAND_TV_NTSC_M = 3, /**< NTSC-M TV band*/ | ||
725 | HPI_TUNER_BAND_TV = 3, /* use TV_NTSC_M */ | ||
726 | HPI_TUNER_BAND_FM_STEREO = 4, /**< FM band (stereo) */ | ||
727 | HPI_TUNER_BAND_AUX = 5, /**< auxiliary input */ | ||
728 | HPI_TUNER_BAND_TV_PAL_BG = 6, /**< PAL-B/G TV band*/ | ||
729 | HPI_TUNER_BAND_TV_PAL_I = 7, /**< PAL-I TV band*/ | ||
730 | HPI_TUNER_BAND_TV_PAL_DK = 8, /**< PAL-D/K TV band*/ | ||
731 | HPI_TUNER_BAND_TV_SECAM_L = 9, /**< SECAM-L TV band*/ | ||
732 | HPI_TUNER_BAND_LAST = 9 /**< the index of the last tuner band. */ | ||
733 | }; | ||
734 | |||
735 | /** Tuner mode attributes | ||
736 | |||
737 | Used by HPI_Tuner_SetMode(), HPI_Tuner_GetMode() | ||
738 | \ingroup tuner | ||
739 | |||
740 | */ | ||
741 | enum HPI_TUNER_MODES { | ||
742 | HPI_TUNER_MODE_RSS = 1, /**< control RSS */ | ||
743 | HPI_TUNER_MODE_RDS = 2 /**< control RBDS/RDS */ | ||
744 | }; | ||
745 | |||
746 | /** Tuner mode attribute values | ||
747 | |||
748 | Used by HPI_Tuner_SetMode(), HPI_Tuner_GetMode() | ||
749 | \ingroup tuner | ||
750 | */ | ||
751 | enum HPI_TUNER_MODE_VALUES { | ||
752 | /* RSS attribute values */ | ||
753 | HPI_TUNER_MODE_RSS_DISABLE = 0, /**< RSS disable */ | ||
754 | HPI_TUNER_MODE_RSS_ENABLE = 1, /**< RSS enable */ | ||
755 | |||
756 | /* RDS mode attributes */ | ||
757 | HPI_TUNER_MODE_RDS_DISABLE = 0, /**< RDS - disabled */ | ||
758 | HPI_TUNER_MODE_RDS_RDS = 1, /**< RDS - RDS mode */ | ||
759 | HPI_TUNER_MODE_RDS_RBDS = 2 /**< RDS - RBDS mode */ | ||
760 | }; | ||
761 | |||
762 | /** Tuner Level settings | ||
763 | \ingroup tuner | ||
764 | */ | ||
765 | enum HPI_TUNER_LEVEL { | ||
766 | HPI_TUNER_LEVEL_AVERAGE = 0, | ||
767 | HPI_TUNER_LEVEL_RAW = 1 | ||
768 | }; | ||
769 | |||
770 | /** Tuner Status Bits | ||
771 | |||
772 | These bitfield values are returned by a call to HPI_Tuner_GetStatus(). | ||
773 | Multiple fields are returned from a single call. | ||
774 | \ingroup tuner | ||
775 | */ | ||
776 | enum HPI_TUNER_STATUS_BITS { | ||
777 | HPI_TUNER_VIDEO_COLOR_PRESENT = 0x0001, /**< video color is present. */ | ||
778 | HPI_TUNER_VIDEO_IS_60HZ = 0x0020, /**< 60 hz video detected. */ | ||
779 | HPI_TUNER_VIDEO_HORZ_SYNC_MISSING = 0x0040, /**< video HSYNC is missing. */ | ||
780 | HPI_TUNER_VIDEO_STATUS_VALID = 0x0100, /**< video status is valid. */ | ||
781 | HPI_TUNER_PLL_LOCKED = 0x1000, /**< the tuner's PLL is locked. */ | ||
782 | HPI_TUNER_FM_STEREO = 0x2000, /**< tuner reports back FM stereo. */ | ||
783 | HPI_TUNER_DIGITAL = 0x0200, /**< tuner reports digital programming. */ | ||
784 | HPI_TUNER_MULTIPROGRAM = 0x0400 /**< tuner reports multiple programs. */ | ||
785 | }; | ||
786 | |||
787 | /** Channel Modes | ||
788 | Used for HPI_ChannelModeSet/Get() | ||
789 | \ingroup channelmode | ||
790 | */ | ||
791 | enum HPI_CHANNEL_MODES { | ||
792 | /** Left channel out = left channel in, Right channel out = right channel in. */ | ||
793 | HPI_CHANNEL_MODE_NORMAL = 1, | ||
794 | /** Left channel out = right channel in, Right channel out = left channel in. */ | ||
795 | HPI_CHANNEL_MODE_SWAP = 2, | ||
796 | /** Left channel out = left channel in, Right channel out = left channel in. */ | ||
797 | HPI_CHANNEL_MODE_LEFT_TO_STEREO = 3, | ||
798 | /** Left channel out = right channel in, Right channel out = right channel in.*/ | ||
799 | HPI_CHANNEL_MODE_RIGHT_TO_STEREO = 4, | ||
800 | /** Left channel out = (left channel in + right channel in)/2, | ||
801 | Right channel out = mute. */ | ||
802 | HPI_CHANNEL_MODE_STEREO_TO_LEFT = 5, | ||
803 | /** Left channel out = mute, | ||
804 | Right channel out = (right channel in + left channel in)/2. */ | ||
805 | HPI_CHANNEL_MODE_STEREO_TO_RIGHT = 6, | ||
806 | HPI_CHANNEL_MODE_LAST = 6 | ||
807 | }; | ||
808 | |||
809 | /** SampleClock source values | ||
810 | \ingroup sampleclock | ||
811 | */ | ||
812 | enum HPI_SAMPLECLOCK_SOURCES { | ||
813 | /** The sampleclock output is derived from its local samplerate generator. | ||
814 | The local samplerate may be set using HPI_SampleClock_SetLocalRate(). */ | ||
815 | HPI_SAMPLECLOCK_SOURCE_LOCAL = 1, | ||
816 | /** \deprecated Use HPI_SAMPLECLOCK_SOURCE_LOCAL instead */ | ||
817 | HPI_SAMPLECLOCK_SOURCE_ADAPTER = 1, | ||
818 | /** The adapter is clocked from a dedicated AES/EBU SampleClock input.*/ | ||
819 | HPI_SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2, | ||
820 | /** From external wordclock connector */ | ||
821 | HPI_SAMPLECLOCK_SOURCE_WORD = 3, | ||
822 | /** Board-to-board header */ | ||
823 | HPI_SAMPLECLOCK_SOURCE_WORD_HEADER = 4, | ||
824 | /** FUTURE - SMPTE clock. */ | ||
825 | HPI_SAMPLECLOCK_SOURCE_SMPTE = 5, | ||
826 | /** One of the aesebu inputs */ | ||
827 | HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT = 6, | ||
828 | /** \deprecated The first aesebu input with a valid signal | ||
829 | Superseded by separate Auto enable flag | ||
830 | */ | ||
831 | HPI_SAMPLECLOCK_SOURCE_AESEBU_AUTO = 7, | ||
832 | /** From a network interface e.g. Cobranet or Livewire at either 48 or 96kHz */ | ||
833 | HPI_SAMPLECLOCK_SOURCE_NETWORK = 8, | ||
834 | /** From previous adjacent module (ASI2416 only)*/ | ||
835 | HPI_SAMPLECLOCK_SOURCE_PREV_MODULE = 10, | ||
836 | /*! Update this if you add a new clock source.*/ | ||
837 | HPI_SAMPLECLOCK_SOURCE_LAST = 10 | ||
838 | }; | ||
839 | |||
840 | /** Equalizer filter types. Used by HPI_ParametricEQ_SetBand() | ||
841 | \ingroup parmeq | ||
842 | */ | ||
843 | enum HPI_FILTER_TYPE { | ||
844 | HPI_FILTER_TYPE_BYPASS = 0, /**< filter is turned off */ | ||
845 | |||
846 | HPI_FILTER_TYPE_LOWSHELF = 1, /**< EQ low shelf */ | ||
847 | HPI_FILTER_TYPE_HIGHSHELF = 2, /**< EQ high shelf */ | ||
848 | HPI_FILTER_TYPE_EQ_BAND = 3, /**< EQ gain */ | ||
849 | |||
850 | HPI_FILTER_TYPE_LOWPASS = 4, /**< standard low pass */ | ||
851 | HPI_FILTER_TYPE_HIGHPASS = 5, /**< standard high pass */ | ||
852 | HPI_FILTER_TYPE_BANDPASS = 6, /**< standard band pass */ | ||
853 | HPI_FILTER_TYPE_BANDSTOP = 7 /**< standard band stop/notch */ | ||
854 | }; | ||
855 | |||
856 | /** Async Event sources | ||
857 | \ingroup async | ||
858 | */ | ||
859 | enum ASYNC_EVENT_SOURCES { | ||
860 | HPI_ASYNC_EVENT_GPIO = 1, /**< GPIO event. */ | ||
861 | HPI_ASYNC_EVENT_SILENCE = 2, /**< silence event detected. */ | ||
862 | HPI_ASYNC_EVENT_TONE = 3 /**< tone event detected. */ | ||
863 | }; | ||
864 | /*******************************************/ | ||
865 | /** HPI Error codes | ||
866 | |||
867 | Almost all HPI functions return an error code | ||
868 | A return value of zero means there was no error. | ||
869 | Otherwise one of these error codes is returned. | ||
870 | Error codes can be converted to a descriptive string using HPI_GetErrorText() | ||
871 | |||
872 | \note When a new error code is added HPI_GetErrorText() MUST be updated. | ||
873 | \note Codes 1-100 are reserved for driver use | ||
874 | \ingroup utility | ||
875 | */ | ||
876 | enum HPI_ERROR_CODES { | ||
877 | /** Message type does not exist. */ | ||
878 | HPI_ERROR_INVALID_TYPE = 100, | ||
879 | /** Object type does not exist. */ | ||
880 | HPI_ERROR_INVALID_OBJ = 101, | ||
881 | /** Function does not exist. */ | ||
882 | HPI_ERROR_INVALID_FUNC = 102, | ||
883 | /** The specified object (adapter/Stream) does not exist. */ | ||
884 | HPI_ERROR_INVALID_OBJ_INDEX = 103, | ||
885 | /** Trying to access an object that has not been opened yet. */ | ||
886 | HPI_ERROR_OBJ_NOT_OPEN = 104, | ||
887 | /** Trying to open an already open object. */ | ||
888 | HPI_ERROR_OBJ_ALREADY_OPEN = 105, | ||
889 | /** PCI, ISA resource not valid. */ | ||
890 | HPI_ERROR_INVALID_RESOURCE = 106, | ||
891 | /** GetInfo call from SubSysFindAdapters failed. */ | ||
892 | HPI_ERROR_SUBSYSFINDADAPTERS_GETINFO = 107, | ||
893 | /** Default response was never updated with actual error code. */ | ||
894 | HPI_ERROR_INVALID_RESPONSE = 108, | ||
895 | /** wSize field of response was not updated, | ||
896 | indicating that the message was not processed. */ | ||
897 | HPI_ERROR_PROCESSING_MESSAGE = 109, | ||
898 | /** The network did not respond in a timely manner. */ | ||
899 | HPI_ERROR_NETWORK_TIMEOUT = 110, | ||
900 | /** An HPI handle is invalid (uninitialised?). */ | ||
901 | HPI_ERROR_INVALID_HANDLE = 111, | ||
902 | /** A function or attribute has not been implemented yet. */ | ||
903 | HPI_ERROR_UNIMPLEMENTED = 112, | ||
904 | /** There are too many clients attempting to access a network resource. */ | ||
905 | HPI_ERROR_NETWORK_TOO_MANY_CLIENTS = 113, | ||
906 | /** Response buffer passed to HPI_Message was smaller than returned response */ | ||
907 | HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL = 114, | ||
908 | /** The returned response did not match the sent message */ | ||
909 | HPI_ERROR_RESPONSE_MISMATCH = 115, | ||
910 | |||
911 | /** Too many adapters.*/ | ||
912 | HPI_ERROR_TOO_MANY_ADAPTERS = 200, | ||
913 | /** Bad adpater. */ | ||
914 | HPI_ERROR_BAD_ADAPTER = 201, | ||
915 | /** Adapter number out of range or not set properly. */ | ||
916 | HPI_ERROR_BAD_ADAPTER_NUMBER = 202, | ||
917 | /** 2 adapters with the same adapter number. */ | ||
918 | HPI_DUPLICATE_ADAPTER_NUMBER = 203, | ||
919 | /** DSP code failed to bootload. */ | ||
920 | HPI_ERROR_DSP_BOOTLOAD = 204, | ||
921 | /** Adapter failed DSP code self test. */ | ||
922 | HPI_ERROR_DSP_SELFTEST = 205, | ||
923 | /** Couldn't find or open the DSP code file. */ | ||
924 | HPI_ERROR_DSP_FILE_NOT_FOUND = 206, | ||
925 | /** Internal DSP hardware error. */ | ||
926 | HPI_ERROR_DSP_HARDWARE = 207, | ||
927 | /** Could not allocate memory in DOS. */ | ||
928 | HPI_ERROR_DOS_MEMORY_ALLOC = 208, | ||
929 | /** Could not allocate memory */ | ||
930 | HPI_ERROR_MEMORY_ALLOC = 208, | ||
931 | /** Failed to correctly load/config PLD .*/ | ||
932 | HPI_ERROR_PLD_LOAD = 209, | ||
933 | /** Unexpected end of file, block length too big etc. */ | ||
934 | HPI_ERROR_DSP_FILE_FORMAT = 210, | ||
935 | |||
936 | /** Found but could not open DSP code file. */ | ||
937 | HPI_ERROR_DSP_FILE_ACCESS_DENIED = 211, | ||
938 | /** First DSP code section header not found in DSP file. */ | ||
939 | HPI_ERROR_DSP_FILE_NO_HEADER = 212, | ||
940 | /** File read operation on DSP code file failed. */ | ||
941 | HPI_ERROR_DSP_FILE_READ_ERROR = 213, | ||
942 | /** DSP code for adapter family not found. */ | ||
943 | HPI_ERROR_DSP_SECTION_NOT_FOUND = 214, | ||
944 | /** Other OS specific error opening DSP file. */ | ||
945 | HPI_ERROR_DSP_FILE_OTHER_ERROR = 215, | ||
946 | /** Sharing violation opening DSP code file. */ | ||
947 | HPI_ERROR_DSP_FILE_SHARING_VIOLATION = 216, | ||
948 | /** DSP code section header had size == 0. */ | ||
949 | HPI_ERROR_DSP_FILE_NULL_HEADER = 217, | ||
950 | |||
951 | /** Base number for flash errors. */ | ||
952 | HPI_ERROR_FLASH = 220, | ||
953 | |||
954 | /** Flash has bad checksum */ | ||
955 | HPI_ERROR_BAD_CHECKSUM = (HPI_ERROR_FLASH + 1), | ||
956 | HPI_ERROR_BAD_SEQUENCE = (HPI_ERROR_FLASH + 2), | ||
957 | HPI_ERROR_FLASH_ERASE = (HPI_ERROR_FLASH + 3), | ||
958 | HPI_ERROR_FLASH_PROGRAM = (HPI_ERROR_FLASH + 4), | ||
959 | HPI_ERROR_FLASH_VERIFY = (HPI_ERROR_FLASH + 5), | ||
960 | HPI_ERROR_FLASH_TYPE = (HPI_ERROR_FLASH + 6), | ||
961 | HPI_ERROR_FLASH_START = (HPI_ERROR_FLASH + 7), | ||
962 | |||
963 | /** Reserved for OEMs. */ | ||
964 | HPI_ERROR_RESERVED_1 = 290, | ||
965 | |||
966 | /** Stream does not exist. */ | ||
967 | HPI_ERROR_INVALID_STREAM = 300, | ||
968 | /** Invalid compression format. */ | ||
969 | HPI_ERROR_INVALID_FORMAT = 301, | ||
970 | /** Invalid format samplerate */ | ||
971 | HPI_ERROR_INVALID_SAMPLERATE = 302, | ||
972 | /** Invalid format number of channels. */ | ||
973 | HPI_ERROR_INVALID_CHANNELS = 303, | ||
974 | /** Invalid format bitrate. */ | ||
975 | HPI_ERROR_INVALID_BITRATE = 304, | ||
976 | /** Invalid datasize used for stream read/write. */ | ||
977 | HPI_ERROR_INVALID_DATASIZE = 305, | ||
978 | /** Stream buffer is full during stream write. */ | ||
979 | HPI_ERROR_BUFFER_FULL = 306, | ||
980 | /** Stream buffer is empty during stream read. */ | ||
981 | HPI_ERROR_BUFFER_EMPTY = 307, | ||
982 | /** Invalid datasize used for stream read/write. */ | ||
983 | HPI_ERROR_INVALID_DATA_TRANSFER = 308, | ||
984 | /** Packet ordering error for stream read/write. */ | ||
985 | HPI_ERROR_INVALID_PACKET_ORDER = 309, | ||
986 | |||
987 | /** Object can't do requested operation in its current | ||
988 | state, eg set format, change rec mux state while recording.*/ | ||
989 | HPI_ERROR_INVALID_OPERATION = 310, | ||
990 | |||
991 | /** Where an SRG is shared amongst streams, an incompatible samplerate is one | ||
992 | that is different to any currently playing or recording stream. */ | ||
993 | HPI_ERROR_INCOMPATIBLE_SAMPLERATE = 311, | ||
994 | /** Adapter mode is illegal.*/ | ||
995 | HPI_ERROR_BAD_ADAPTER_MODE = 312, | ||
996 | |||
997 | /** There have been too many attempts to set the adapter's | ||
998 | capabilities (using bad keys), the card should be returned | ||
999 | to ASI if further capabilities updates are required */ | ||
1000 | HPI_ERROR_TOO_MANY_CAPABILITY_CHANGE_ATTEMPTS = 313, | ||
1001 | /** Streams on different adapters cannot be grouped. */ | ||
1002 | HPI_ERROR_NO_INTERADAPTER_GROUPS = 314, | ||
1003 | /** Streams on different DSPs cannot be grouped. */ | ||
1004 | HPI_ERROR_NO_INTERDSP_GROUPS = 315, | ||
1005 | |||
1006 | /** Invalid mixer node for this adapter. */ | ||
1007 | HPI_ERROR_INVALID_NODE = 400, | ||
1008 | /** Invalid control. */ | ||
1009 | HPI_ERROR_INVALID_CONTROL = 401, | ||
1010 | /** Invalid control value was passed. */ | ||
1011 | HPI_ERROR_INVALID_CONTROL_VALUE = 402, | ||
1012 | /** Control attribute not supported by this control. */ | ||
1013 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE = 403, | ||
1014 | /** Control is disabled. */ | ||
1015 | HPI_ERROR_CONTROL_DISABLED = 404, | ||
1016 | /** I2C transaction failed due to a missing ACK. */ | ||
1017 | HPI_ERROR_CONTROL_I2C_MISSING_ACK = 405, | ||
1018 | /** Control attribute is valid, but not supported by this hardware. */ | ||
1019 | HPI_ERROR_UNSUPPORTED_CONTROL_ATTRIBUTE = 406, | ||
1020 | /** Control is busy, or coming out of | ||
1021 | reset and cannot be accessed at this time. */ | ||
1022 | HPI_ERROR_CONTROL_NOT_READY = 407, | ||
1023 | |||
1024 | /** Non volatile memory */ | ||
1025 | HPI_ERROR_NVMEM_BUSY = 450, | ||
1026 | HPI_ERROR_NVMEM_FULL = 451, | ||
1027 | HPI_ERROR_NVMEM_FAIL = 452, | ||
1028 | |||
1029 | /** I2C */ | ||
1030 | HPI_ERROR_I2C_MISSING_ACK = HPI_ERROR_CONTROL_I2C_MISSING_ACK, | ||
1031 | HPI_ERROR_I2C_BAD_ADR = 460, | ||
1032 | |||
1033 | /** Entity errors */ | ||
1034 | HPI_ERROR_ENTITY_TYPE_MISMATCH = 470, | ||
1035 | HPI_ERROR_ENTITY_ITEM_COUNT = 471, | ||
1036 | HPI_ERROR_ENTITY_TYPE_INVALID = 472, | ||
1037 | HPI_ERROR_ENTITY_ROLE_INVALID = 473, | ||
1038 | |||
1039 | /* AES18 specific errors were 500..507 */ | ||
1040 | |||
1041 | /** custom error to use for debugging */ | ||
1042 | HPI_ERROR_CUSTOM = 600, | ||
1043 | |||
1044 | /** hpioct32.c can't obtain mutex */ | ||
1045 | HPI_ERROR_MUTEX_TIMEOUT = 700, | ||
1046 | |||
1047 | /** errors from HPI backends have values >= this */ | ||
1048 | HPI_ERROR_BACKEND_BASE = 900, | ||
1049 | |||
1050 | /** indicates a cached u16 value is invalid. */ | ||
1051 | HPI_ERROR_ILLEGAL_CACHE_VALUE = 0xffff | ||
1052 | }; | ||
1053 | |||
1054 | /** \defgroup maximums HPI maximum values | ||
1055 | \{ | ||
1056 | */ | ||
1057 | /** Maximum number of adapters per HPI sub-system | ||
1058 | WARNING: modifying this value changes the response structure size.*/ | ||
1059 | #define HPI_MAX_ADAPTERS 20 | ||
1060 | /** Maximum number of in or out streams per adapter */ | ||
1061 | #define HPI_MAX_STREAMS 16 | ||
1062 | #define HPI_MAX_CHANNELS 2 /* per stream */ | ||
1063 | #define HPI_MAX_NODES 8 /* per mixer ? */ | ||
1064 | #define HPI_MAX_CONTROLS 4 /* per node ? */ | ||
1065 | /** maximum number of ancillary bytes per MPEG frame */ | ||
1066 | #define HPI_MAX_ANC_BYTES_PER_FRAME (64) | ||
1067 | #define HPI_STRING_LEN 16 | ||
1068 | |||
1069 | /** Velocity units */ | ||
1070 | #define HPI_OSTREAM_VELOCITY_UNITS 4096 | ||
1071 | /** OutStream timescale units */ | ||
1072 | #define HPI_OSTREAM_TIMESCALE_UNITS 10000 | ||
1073 | /** OutStream timescale passthrough - turns timescaling on in passthough mode */ | ||
1074 | #define HPI_OSTREAM_TIMESCALE_PASSTHROUGH 99999 | ||
1075 | |||
1076 | /**\}*/ | ||
1077 | |||
1078 | /* ////////////////////////////////////////////////////////////////////// */ | ||
1079 | /* STRUCTURES */ | ||
1080 | #ifndef DISABLE_PRAGMA_PACK1 | ||
1081 | #pragma pack(push, 1) | ||
1082 | #endif | ||
1083 | |||
1084 | /** Structure containing sample format information. | ||
1085 | See also HPI_FormatCreate(). | ||
1086 | */ | ||
1087 | struct hpi_format { | ||
1088 | u32 sample_rate; | ||
1089 | /**< 11025, 32000, 44100 ... */ | ||
1090 | u32 bit_rate; /**< for MPEG */ | ||
1091 | u32 attributes; | ||
1092 | /**< Stereo/JointStereo/Mono */ | ||
1093 | u16 mode_legacy; | ||
1094 | /**< Legacy ancillary mode or idle bit */ | ||
1095 | u16 unused; /**< unused */ | ||
1096 | u16 channels; /**< 1,2..., (or ancillary mode or idle bit */ | ||
1097 | u16 format; /**< HPI_FORMAT_PCM16, _MPEG etc. see #HPI_FORMATS. */ | ||
1098 | }; | ||
1099 | |||
1100 | struct hpi_anc_frame { | ||
1101 | u32 valid_bits_in_this_frame; | ||
1102 | u8 b_data[HPI_MAX_ANC_BYTES_PER_FRAME]; | ||
1103 | }; | ||
1104 | |||
1105 | /** An object for containing a single async event. | ||
1106 | */ | ||
1107 | struct hpi_async_event { | ||
1108 | u16 event_type; /**< type of event. \sa async_event */ | ||
1109 | u16 sequence; /**< sequence number, allows lost event detection */ | ||
1110 | u32 state; /**< new state */ | ||
1111 | u32 h_object; /**< handle to the object returning the event. */ | ||
1112 | union { | ||
1113 | struct { | ||
1114 | u16 index; /**< GPIO bit index. */ | ||
1115 | } gpio; | ||
1116 | struct { | ||
1117 | u16 node_index; /**< what node is the control on ? */ | ||
1118 | u16 node_type; /**< what type of node is the control on ? */ | ||
1119 | } control; | ||
1120 | } u; | ||
1121 | }; | ||
1122 | |||
1123 | /*/////////////////////////////////////////////////////////////////////////// */ | ||
1124 | /* Public HPI Entity related definitions */ | ||
1125 | |||
1126 | struct hpi_entity; | ||
1127 | |||
1128 | enum e_entity_type { | ||
1129 | entity_type_null, | ||
1130 | entity_type_sequence, /* sequence of potentially heterogeneous TLV entities */ | ||
1131 | |||
1132 | entity_type_reference, /* refers to a TLV entity or NULL */ | ||
1133 | |||
1134 | entity_type_int, /* 32 bit */ | ||
1135 | entity_type_float, /* ieee754 binary 32 bit encoding */ | ||
1136 | entity_type_double, | ||
1137 | |||
1138 | entity_type_cstring, | ||
1139 | entity_type_octet, | ||
1140 | entity_type_ip4_address, | ||
1141 | entity_type_ip6_address, | ||
1142 | entity_type_mac_address, | ||
1143 | |||
1144 | LAST_ENTITY_TYPE | ||
1145 | }; | ||
1146 | |||
1147 | enum e_entity_role { | ||
1148 | entity_role_null, | ||
1149 | entity_role_value, | ||
1150 | entity_role_classname, | ||
1151 | |||
1152 | entity_role_units, | ||
1153 | entity_role_flags, | ||
1154 | entity_role_range, | ||
1155 | |||
1156 | entity_role_mapping, | ||
1157 | entity_role_enum, | ||
1158 | |||
1159 | entity_role_instance_of, | ||
1160 | entity_role_depends_on, | ||
1161 | entity_role_member_of_group, | ||
1162 | entity_role_value_constraint, | ||
1163 | entity_role_parameter_port, | ||
1164 | |||
1165 | entity_role_block, | ||
1166 | entity_role_node_group, | ||
1167 | entity_role_audio_port, | ||
1168 | entity_role_clock_port, | ||
1169 | LAST_ENTITY_ROLE | ||
1170 | }; | ||
1171 | |||
1172 | /* skip host side function declarations for | ||
1173 | DSP compile and documentation extraction */ | ||
1174 | |||
1175 | struct hpi_hsubsys { | ||
1176 | int not_really_used; | ||
1177 | }; | ||
1178 | |||
1179 | #ifndef DISABLE_PRAGMA_PACK1 | ||
1180 | #pragma pack(pop) | ||
1181 | #endif | ||
1182 | |||
1183 | /*////////////////////////////////////////////////////////////////////////// */ | ||
1184 | /* HPI FUNCTIONS */ | ||
1185 | |||
1186 | /*/////////////////////////// */ | ||
1187 | /* DATA and FORMAT and STREAM */ | ||
1188 | |||
1189 | u16 hpi_stream_estimate_buffer_size(struct hpi_format *pF, | ||
1190 | u32 host_polling_rate_in_milli_seconds, u32 *recommended_buffer_size); | ||
1191 | |||
1192 | /*/////////// */ | ||
1193 | /* SUB SYSTEM */ | ||
1194 | struct hpi_hsubsys *hpi_subsys_create(void | ||
1195 | ); | ||
1196 | |||
1197 | void hpi_subsys_free(const struct hpi_hsubsys *ph_subsys); | ||
1198 | |||
1199 | u16 hpi_subsys_get_version(const struct hpi_hsubsys *ph_subsys, | ||
1200 | u32 *pversion); | ||
1201 | |||
1202 | u16 hpi_subsys_get_version_ex(const struct hpi_hsubsys *ph_subsys, | ||
1203 | u32 *pversion_ex); | ||
1204 | |||
1205 | u16 hpi_subsys_get_info(const struct hpi_hsubsys *ph_subsys, u32 *pversion, | ||
1206 | u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length); | ||
1207 | |||
1208 | u16 hpi_subsys_find_adapters(const struct hpi_hsubsys *ph_subsys, | ||
1209 | u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length); | ||
1210 | |||
1211 | u16 hpi_subsys_get_num_adapters(const struct hpi_hsubsys *ph_subsys, | ||
1212 | int *pn_num_adapters); | ||
1213 | |||
1214 | u16 hpi_subsys_get_adapter(const struct hpi_hsubsys *ph_subsys, int iterator, | ||
1215 | u32 *padapter_index, u16 *pw_adapter_type); | ||
1216 | |||
1217 | u16 hpi_subsys_ssx2_bypass(const struct hpi_hsubsys *ph_subsys, u16 bypass); | ||
1218 | |||
1219 | u16 hpi_subsys_set_host_network_interface(const struct hpi_hsubsys *ph_subsys, | ||
1220 | const char *sz_interface); | ||
1221 | |||
1222 | /*///////// */ | ||
1223 | /* ADAPTER */ | ||
1224 | |||
1225 | u16 hpi_adapter_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index); | ||
1226 | |||
1227 | u16 hpi_adapter_close(const struct hpi_hsubsys *ph_subsys, u16 adapter_index); | ||
1228 | |||
1229 | u16 hpi_adapter_get_info(const struct hpi_hsubsys *ph_subsys, | ||
1230 | u16 adapter_index, u16 *pw_num_outstreams, u16 *pw_num_instreams, | ||
1231 | u16 *pw_version, u32 *pserial_number, u16 *pw_adapter_type); | ||
1232 | |||
1233 | u16 hpi_adapter_get_module_by_index(const struct hpi_hsubsys *ph_subsys, | ||
1234 | u16 adapter_index, u16 module_index, u16 *pw_num_outputs, | ||
1235 | u16 *pw_num_inputs, u16 *pw_version, u32 *pserial_number, | ||
1236 | u16 *pw_module_type, u32 *ph_module); | ||
1237 | |||
1238 | u16 hpi_adapter_set_mode(const struct hpi_hsubsys *ph_subsys, | ||
1239 | u16 adapter_index, u32 adapter_mode); | ||
1240 | |||
1241 | u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys, | ||
1242 | u16 adapter_index, u32 adapter_mode, u16 query_or_set); | ||
1243 | |||
1244 | u16 hpi_adapter_get_mode(const struct hpi_hsubsys *ph_subsys, | ||
1245 | u16 adapter_index, u32 *padapter_mode); | ||
1246 | |||
1247 | u16 hpi_adapter_get_assert(const struct hpi_hsubsys *ph_subsys, | ||
1248 | u16 adapter_index, u16 *assert_present, char *psz_assert, | ||
1249 | u16 *pw_line_number); | ||
1250 | |||
1251 | u16 hpi_adapter_get_assert_ex(const struct hpi_hsubsys *ph_subsys, | ||
1252 | u16 adapter_index, u16 *assert_present, char *psz_assert, | ||
1253 | u32 *pline_number, u16 *pw_assert_on_dsp); | ||
1254 | |||
1255 | u16 hpi_adapter_test_assert(const struct hpi_hsubsys *ph_subsys, | ||
1256 | u16 adapter_index, u16 assert_id); | ||
1257 | |||
1258 | u16 hpi_adapter_enable_capability(const struct hpi_hsubsys *ph_subsys, | ||
1259 | u16 adapter_index, u16 capability, u32 key); | ||
1260 | |||
1261 | u16 hpi_adapter_self_test(const struct hpi_hsubsys *ph_subsys, | ||
1262 | u16 adapter_index); | ||
1263 | |||
1264 | u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys, | ||
1265 | u16 adapter_index, u32 dsp_address, char *p_bytes, int *count_bytes); | ||
1266 | |||
1267 | u16 hpi_adapter_set_property(const struct hpi_hsubsys *ph_subsys, | ||
1268 | u16 adapter_index, u16 property, u16 paramter1, u16 paramter2); | ||
1269 | |||
1270 | u16 hpi_adapter_get_property(const struct hpi_hsubsys *ph_subsys, | ||
1271 | u16 adapter_index, u16 property, u16 *pw_paramter1, | ||
1272 | u16 *pw_paramter2); | ||
1273 | |||
1274 | u16 hpi_adapter_enumerate_property(const struct hpi_hsubsys *ph_subsys, | ||
1275 | u16 adapter_index, u16 index, u16 what_to_enumerate, | ||
1276 | u16 property_index, u32 *psetting); | ||
1277 | |||
1278 | /*////////////// */ | ||
1279 | /* NonVol Memory */ | ||
1280 | u16 hpi_nv_memory_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1281 | u32 *ph_nv_memory, u16 *pw_size_in_bytes); | ||
1282 | |||
1283 | u16 hpi_nv_memory_read_byte(const struct hpi_hsubsys *ph_subsys, | ||
1284 | u32 h_nv_memory, u16 index, u16 *pw_data); | ||
1285 | |||
1286 | u16 hpi_nv_memory_write_byte(const struct hpi_hsubsys *ph_subsys, | ||
1287 | u32 h_nv_memory, u16 index, u16 data); | ||
1288 | |||
1289 | /*////////////// */ | ||
1290 | /* Digital I/O */ | ||
1291 | u16 hpi_gpio_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1292 | u32 *ph_gpio, u16 *pw_number_input_bits, u16 *pw_number_output_bits); | ||
1293 | |||
1294 | u16 hpi_gpio_read_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio, | ||
1295 | u16 bit_index, u16 *pw_bit_data); | ||
1296 | |||
1297 | u16 hpi_gpio_read_all_bits(const struct hpi_hsubsys *ph_subsys, u32 h_gpio, | ||
1298 | u16 aw_all_bit_data[4] | ||
1299 | ); | ||
1300 | |||
1301 | u16 hpi_gpio_write_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio, | ||
1302 | u16 bit_index, u16 bit_data); | ||
1303 | |||
1304 | u16 hpi_gpio_write_status(const struct hpi_hsubsys *ph_subsys, u32 h_gpio, | ||
1305 | u16 aw_all_bit_data[4] | ||
1306 | ); | ||
1307 | |||
1308 | /**********************/ | ||
1309 | /* Async Event Object */ | ||
1310 | /**********************/ | ||
1311 | u16 hpi_async_event_open(const struct hpi_hsubsys *ph_subsys, | ||
1312 | u16 adapter_index, u32 *ph_async); | ||
1313 | |||
1314 | u16 hpi_async_event_close(const struct hpi_hsubsys *ph_subsys, u32 h_async); | ||
1315 | |||
1316 | u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async, | ||
1317 | u16 maximum_events, struct hpi_async_event *p_events, | ||
1318 | u16 *pw_number_returned); | ||
1319 | |||
1320 | u16 hpi_async_event_get_count(const struct hpi_hsubsys *ph_subsys, | ||
1321 | u32 h_async, u16 *pw_count); | ||
1322 | |||
1323 | u16 hpi_async_event_get(const struct hpi_hsubsys *ph_subsys, u32 h_async, | ||
1324 | u16 maximum_events, struct hpi_async_event *p_events, | ||
1325 | u16 *pw_number_returned); | ||
1326 | |||
1327 | /*/////////// */ | ||
1328 | /* WATCH-DOG */ | ||
1329 | u16 hpi_watchdog_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1330 | u32 *ph_watchdog); | ||
1331 | |||
1332 | u16 hpi_watchdog_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog, | ||
1333 | u32 time_millisec); | ||
1334 | |||
1335 | u16 hpi_watchdog_ping(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog); | ||
1336 | |||
1337 | /**************/ | ||
1338 | /* OUT STREAM */ | ||
1339 | /**************/ | ||
1340 | u16 hpi_outstream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1341 | u16 outstream_index, u32 *ph_outstream); | ||
1342 | |||
1343 | u16 hpi_outstream_close(const struct hpi_hsubsys *ph_subsys, u32 h_outstream); | ||
1344 | |||
1345 | u16 hpi_outstream_get_info_ex(const struct hpi_hsubsys *ph_subsys, | ||
1346 | u32 h_outstream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_to_play, | ||
1347 | u32 *psamples_played, u32 *pauxiliary_data_to_play); | ||
1348 | |||
1349 | u16 hpi_outstream_write_buf(const struct hpi_hsubsys *ph_subsys, | ||
1350 | u32 h_outstream, const u8 *pb_write_buf, u32 bytes_to_write, | ||
1351 | const struct hpi_format *p_format); | ||
1352 | |||
1353 | u16 hpi_outstream_start(const struct hpi_hsubsys *ph_subsys, u32 h_outstream); | ||
1354 | |||
1355 | u16 hpi_outstream_wait_start(const struct hpi_hsubsys *ph_subsys, | ||
1356 | u32 h_outstream); | ||
1357 | |||
1358 | u16 hpi_outstream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_outstream); | ||
1359 | |||
1360 | u16 hpi_outstream_sinegen(const struct hpi_hsubsys *ph_subsys, | ||
1361 | u32 h_outstream); | ||
1362 | |||
1363 | u16 hpi_outstream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_outstream); | ||
1364 | |||
1365 | u16 hpi_outstream_query_format(const struct hpi_hsubsys *ph_subsys, | ||
1366 | u32 h_outstream, struct hpi_format *p_format); | ||
1367 | |||
1368 | u16 hpi_outstream_set_format(const struct hpi_hsubsys *ph_subsys, | ||
1369 | u32 h_outstream, struct hpi_format *p_format); | ||
1370 | |||
1371 | u16 hpi_outstream_set_punch_in_out(const struct hpi_hsubsys *ph_subsys, | ||
1372 | u32 h_outstream, u32 punch_in_sample, u32 punch_out_sample); | ||
1373 | |||
1374 | u16 hpi_outstream_set_velocity(const struct hpi_hsubsys *ph_subsys, | ||
1375 | u32 h_outstream, short velocity); | ||
1376 | |||
1377 | u16 hpi_outstream_ancillary_reset(const struct hpi_hsubsys *ph_subsys, | ||
1378 | u32 h_outstream, u16 mode); | ||
1379 | |||
1380 | u16 hpi_outstream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys, | ||
1381 | u32 h_outstream, u32 *pframes_available); | ||
1382 | |||
1383 | u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys, | ||
1384 | u32 h_outstream, struct hpi_anc_frame *p_anc_frame_buffer, | ||
1385 | u32 anc_frame_buffer_size_in_bytes, | ||
1386 | u32 number_of_ancillary_frames_to_read); | ||
1387 | |||
1388 | u16 hpi_outstream_set_time_scale(const struct hpi_hsubsys *ph_subsys, | ||
1389 | u32 h_outstream, u32 time_scaleX10000); | ||
1390 | |||
1391 | u16 hpi_outstream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys, | ||
1392 | u32 h_outstream, u32 size_in_bytes); | ||
1393 | |||
1394 | u16 hpi_outstream_host_buffer_free(const struct hpi_hsubsys *ph_subsys, | ||
1395 | u32 h_outstream); | ||
1396 | |||
1397 | u16 hpi_outstream_group_add(const struct hpi_hsubsys *ph_subsys, | ||
1398 | u32 h_outstream, u32 h_stream); | ||
1399 | |||
1400 | u16 hpi_outstream_group_get_map(const struct hpi_hsubsys *ph_subsys, | ||
1401 | u32 h_outstream, u32 *poutstream_map, u32 *pinstream_map); | ||
1402 | |||
1403 | u16 hpi_outstream_group_reset(const struct hpi_hsubsys *ph_subsys, | ||
1404 | u32 h_outstream); | ||
1405 | |||
1406 | /*////////// */ | ||
1407 | /* IN_STREAM */ | ||
1408 | u16 hpi_instream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1409 | u16 instream_index, u32 *ph_instream); | ||
1410 | |||
1411 | u16 hpi_instream_close(const struct hpi_hsubsys *ph_subsys, u32 h_instream); | ||
1412 | |||
1413 | u16 hpi_instream_query_format(const struct hpi_hsubsys *ph_subsys, | ||
1414 | u32 h_instream, const struct hpi_format *p_format); | ||
1415 | |||
1416 | u16 hpi_instream_set_format(const struct hpi_hsubsys *ph_subsys, | ||
1417 | u32 h_instream, const struct hpi_format *p_format); | ||
1418 | |||
1419 | u16 hpi_instream_read_buf(const struct hpi_hsubsys *ph_subsys, u32 h_instream, | ||
1420 | u8 *pb_read_buf, u32 bytes_to_read); | ||
1421 | |||
1422 | u16 hpi_instream_start(const struct hpi_hsubsys *ph_subsys, u32 h_instream); | ||
1423 | |||
1424 | u16 hpi_instream_wait_start(const struct hpi_hsubsys *ph_subsys, | ||
1425 | u32 h_instream); | ||
1426 | |||
1427 | u16 hpi_instream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_instream); | ||
1428 | |||
1429 | u16 hpi_instream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_instream); | ||
1430 | |||
1431 | u16 hpi_instream_get_info_ex(const struct hpi_hsubsys *ph_subsys, | ||
1432 | u32 h_instream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_recorded, | ||
1433 | u32 *psamples_recorded, u32 *pauxiliary_data_recorded); | ||
1434 | |||
1435 | u16 hpi_instream_ancillary_reset(const struct hpi_hsubsys *ph_subsys, | ||
1436 | u32 h_instream, u16 bytes_per_frame, u16 mode, u16 alignment, | ||
1437 | u16 idle_bit); | ||
1438 | |||
1439 | u16 hpi_instream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys, | ||
1440 | u32 h_instream, u32 *pframe_space); | ||
1441 | |||
1442 | u16 hpi_instream_ancillary_write(const struct hpi_hsubsys *ph_subsys, | ||
1443 | u32 h_instream, const struct hpi_anc_frame *p_anc_frame_buffer, | ||
1444 | u32 anc_frame_buffer_size_in_bytes, | ||
1445 | u32 number_of_ancillary_frames_to_write); | ||
1446 | |||
1447 | u16 hpi_instream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys, | ||
1448 | u32 h_instream, u32 size_in_bytes); | ||
1449 | |||
1450 | u16 hpi_instream_host_buffer_free(const struct hpi_hsubsys *ph_subsys, | ||
1451 | u32 h_instream); | ||
1452 | |||
1453 | u16 hpi_instream_group_add(const struct hpi_hsubsys *ph_subsys, | ||
1454 | u32 h_instream, u32 h_stream); | ||
1455 | |||
1456 | u16 hpi_instream_group_get_map(const struct hpi_hsubsys *ph_subsys, | ||
1457 | u32 h_instream, u32 *poutstream_map, u32 *pinstream_map); | ||
1458 | |||
1459 | u16 hpi_instream_group_reset(const struct hpi_hsubsys *ph_subsys, | ||
1460 | u32 h_instream); | ||
1461 | |||
1462 | /*********/ | ||
1463 | /* MIXER */ | ||
1464 | /*********/ | ||
1465 | u16 hpi_mixer_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1466 | u32 *ph_mixer); | ||
1467 | |||
1468 | u16 hpi_mixer_close(const struct hpi_hsubsys *ph_subsys, u32 h_mixer); | ||
1469 | |||
1470 | u16 hpi_mixer_get_control(const struct hpi_hsubsys *ph_subsys, u32 h_mixer, | ||
1471 | u16 src_node_type, u16 src_node_type_index, u16 dst_node_type, | ||
1472 | u16 dst_node_type_index, u16 control_type, u32 *ph_control); | ||
1473 | |||
1474 | u16 hpi_mixer_get_control_by_index(const struct hpi_hsubsys *ph_subsys, | ||
1475 | u32 h_mixer, u16 control_index, u16 *pw_src_node_type, | ||
1476 | u16 *pw_src_node_index, u16 *pw_dst_node_type, u16 *pw_dst_node_index, | ||
1477 | u16 *pw_control_type, u32 *ph_control); | ||
1478 | |||
1479 | u16 hpi_mixer_store(const struct hpi_hsubsys *ph_subsys, u32 h_mixer, | ||
1480 | enum HPI_MIXER_STORE_COMMAND command, u16 index); | ||
1481 | /*************************/ | ||
1482 | /* mixer CONTROLS */ | ||
1483 | /*************************/ | ||
1484 | /*************************/ | ||
1485 | /* volume control */ | ||
1486 | /*************************/ | ||
1487 | u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1488 | short an_gain0_01dB[HPI_MAX_CHANNELS] | ||
1489 | ); | ||
1490 | |||
1491 | u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1492 | short an_gain0_01dB_out[HPI_MAX_CHANNELS] | ||
1493 | ); | ||
1494 | |||
1495 | #define hpi_volume_get_range hpi_volume_query_range | ||
1496 | u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1497 | short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB); | ||
1498 | |||
1499 | u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys, | ||
1500 | const u32 h_volume, u32 *p_channels); | ||
1501 | |||
1502 | u16 hpi_volume_auto_fade(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1503 | short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms); | ||
1504 | |||
1505 | u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys, | ||
1506 | u32 h_control, short an_stop_gain0_01dB[HPI_MAX_CHANNELS], | ||
1507 | u32 duration_ms, u16 profile); | ||
1508 | |||
1509 | /*************************/ | ||
1510 | /* level control */ | ||
1511 | /*************************/ | ||
1512 | u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1513 | short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB); | ||
1514 | |||
1515 | u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1516 | short an_gain0_01dB[HPI_MAX_CHANNELS] | ||
1517 | ); | ||
1518 | |||
1519 | u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1520 | short an_gain0_01dB_out[HPI_MAX_CHANNELS] | ||
1521 | ); | ||
1522 | |||
1523 | /*************************/ | ||
1524 | /* meter control */ | ||
1525 | /*************************/ | ||
1526 | u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys, | ||
1527 | const u32 h_meter, u32 *p_channels); | ||
1528 | |||
1529 | u16 hpi_meter_get_peak(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1530 | short an_peak0_01dB_out[HPI_MAX_CHANNELS] | ||
1531 | ); | ||
1532 | |||
1533 | u16 hpi_meter_get_rms(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1534 | short an_peak0_01dB_out[HPI_MAX_CHANNELS] | ||
1535 | ); | ||
1536 | |||
1537 | u16 hpi_meter_set_peak_ballistics(const struct hpi_hsubsys *ph_subsys, | ||
1538 | u32 h_control, u16 attack, u16 decay); | ||
1539 | |||
1540 | u16 hpi_meter_set_rms_ballistics(const struct hpi_hsubsys *ph_subsys, | ||
1541 | u32 h_control, u16 attack, u16 decay); | ||
1542 | |||
1543 | u16 hpi_meter_get_peak_ballistics(const struct hpi_hsubsys *ph_subsys, | ||
1544 | u32 h_control, u16 *attack, u16 *decay); | ||
1545 | |||
1546 | u16 hpi_meter_get_rms_ballistics(const struct hpi_hsubsys *ph_subsys, | ||
1547 | u32 h_control, u16 *attack, u16 *decay); | ||
1548 | |||
1549 | /*************************/ | ||
1550 | /* channel mode control */ | ||
1551 | /*************************/ | ||
1552 | u16 hpi_channel_mode_query_mode(const struct hpi_hsubsys *ph_subsys, | ||
1553 | const u32 h_mode, const u32 index, u16 *pw_mode); | ||
1554 | |||
1555 | u16 hpi_channel_mode_set(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1556 | u16 mode); | ||
1557 | |||
1558 | u16 hpi_channel_mode_get(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1559 | u16 *mode); | ||
1560 | |||
1561 | /*************************/ | ||
1562 | /* Tuner control */ | ||
1563 | /*************************/ | ||
1564 | u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys, | ||
1565 | const u32 h_tuner, const u32 index, u16 *pw_band); | ||
1566 | |||
1567 | u16 hpi_tuner_set_band(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1568 | u16 band); | ||
1569 | |||
1570 | u16 hpi_tuner_get_band(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1571 | u16 *pw_band); | ||
1572 | |||
1573 | u16 hpi_tuner_query_frequency(const struct hpi_hsubsys *ph_subsys, | ||
1574 | const u32 h_tuner, const u32 index, const u16 band, u32 *pfreq); | ||
1575 | |||
1576 | u16 hpi_tuner_set_frequency(const struct hpi_hsubsys *ph_subsys, | ||
1577 | u32 h_control, u32 freq_ink_hz); | ||
1578 | |||
1579 | u16 hpi_tuner_get_frequency(const struct hpi_hsubsys *ph_subsys, | ||
1580 | u32 h_control, u32 *pw_freq_ink_hz); | ||
1581 | |||
1582 | u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1583 | short *pw_level); | ||
1584 | |||
1585 | u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys, | ||
1586 | u32 h_control, short *pw_level); | ||
1587 | |||
1588 | u16 hpi_tuner_query_gain(const struct hpi_hsubsys *ph_subsys, | ||
1589 | const u32 h_tuner, const u32 index, u16 *pw_gain); | ||
1590 | |||
1591 | u16 hpi_tuner_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1592 | short gain); | ||
1593 | |||
1594 | u16 hpi_tuner_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1595 | short *pn_gain); | ||
1596 | |||
1597 | u16 hpi_tuner_get_status(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1598 | u16 *pw_status_mask, u16 *pw_status); | ||
1599 | |||
1600 | u16 hpi_tuner_set_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1601 | u32 mode, u32 value); | ||
1602 | |||
1603 | u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1604 | u32 mode, u32 *pn_value); | ||
1605 | |||
1606 | u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1607 | char *p_rds_data); | ||
1608 | |||
1609 | u16 hpi_tuner_query_deemphasis(const struct hpi_hsubsys *ph_subsys, | ||
1610 | const u32 h_tuner, const u32 index, const u16 band, u32 *pdeemphasis); | ||
1611 | |||
1612 | u16 hpi_tuner_set_deemphasis(const struct hpi_hsubsys *ph_subsys, | ||
1613 | u32 h_control, u32 deemphasis); | ||
1614 | u16 hpi_tuner_get_deemphasis(const struct hpi_hsubsys *ph_subsys, | ||
1615 | u32 h_control, u32 *pdeemphasis); | ||
1616 | |||
1617 | u16 hpi_tuner_query_program(const struct hpi_hsubsys *ph_subsys, | ||
1618 | const u32 h_tuner, u32 *pbitmap_program); | ||
1619 | |||
1620 | u16 hpi_tuner_set_program(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1621 | u32 program); | ||
1622 | |||
1623 | u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1624 | u32 *pprogram); | ||
1625 | |||
1626 | u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys, | ||
1627 | u32 h_control, char *psz_dsp_version, const u32 string_size); | ||
1628 | |||
1629 | u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys, | ||
1630 | u32 h_control, char *psz_sdk_version, const u32 string_size); | ||
1631 | |||
1632 | u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys, | ||
1633 | u32 h_control, u32 *pquality); | ||
1634 | |||
1635 | /****************************/ | ||
1636 | /* PADs control */ | ||
1637 | /****************************/ | ||
1638 | |||
1639 | u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys, | ||
1640 | u32 h_control, char *psz_string, const u32 string_length); | ||
1641 | |||
1642 | u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1643 | char *psz_string, const u32 string_length); | ||
1644 | |||
1645 | u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1646 | char *psz_string, const u32 string_length); | ||
1647 | |||
1648 | u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1649 | char *psz_string, const u32 string_length); | ||
1650 | |||
1651 | u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys, | ||
1652 | u32 h_control, u32 *ppTY); | ||
1653 | |||
1654 | u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1655 | u32 *ppI); | ||
1656 | |||
1657 | u16 HPI_PAD__get_program_type_string(const struct hpi_hsubsys *ph_subsys, | ||
1658 | u32 h_control, const u32 data_type, const u32 pTY, char *psz_string, | ||
1659 | const u32 string_length); | ||
1660 | |||
1661 | /****************************/ | ||
1662 | /* AES/EBU Receiver control */ | ||
1663 | /****************************/ | ||
1664 | u16 HPI_AESEBU__receiver_query_format(const struct hpi_hsubsys *ph_subsys, | ||
1665 | const u32 h_aes_rx, const u32 index, u16 *pw_format); | ||
1666 | |||
1667 | u16 HPI_AESEBU__receiver_set_format(const struct hpi_hsubsys *ph_subsys, | ||
1668 | u32 h_control, u16 source); | ||
1669 | |||
1670 | u16 HPI_AESEBU__receiver_get_format(const struct hpi_hsubsys *ph_subsys, | ||
1671 | u32 h_control, u16 *pw_source); | ||
1672 | |||
1673 | u16 HPI_AESEBU__receiver_get_sample_rate(const struct hpi_hsubsys *ph_subsys, | ||
1674 | u32 h_control, u32 *psample_rate); | ||
1675 | |||
1676 | u16 HPI_AESEBU__receiver_get_user_data(const struct hpi_hsubsys *ph_subsys, | ||
1677 | u32 h_control, u16 index, u16 *pw_data); | ||
1678 | |||
1679 | u16 HPI_AESEBU__receiver_get_channel_status(const struct hpi_hsubsys | ||
1680 | *ph_subsys, u32 h_control, u16 index, u16 *pw_data); | ||
1681 | |||
1682 | u16 HPI_AESEBU__receiver_get_error_status(const struct hpi_hsubsys *ph_subsys, | ||
1683 | u32 h_control, u16 *pw_error_data); | ||
1684 | |||
1685 | /*******************************/ | ||
1686 | /* AES/EBU Transmitter control */ | ||
1687 | /*******************************/ | ||
1688 | u16 HPI_AESEBU__transmitter_set_sample_rate(const struct hpi_hsubsys | ||
1689 | *ph_subsys, u32 h_control, u32 sample_rate); | ||
1690 | |||
1691 | u16 HPI_AESEBU__transmitter_set_user_data(const struct hpi_hsubsys *ph_subsys, | ||
1692 | u32 h_control, u16 index, u16 data); | ||
1693 | |||
1694 | u16 HPI_AESEBU__transmitter_set_channel_status(const struct hpi_hsubsys | ||
1695 | *ph_subsys, u32 h_control, u16 index, u16 data); | ||
1696 | |||
1697 | u16 HPI_AESEBU__transmitter_get_channel_status(const struct hpi_hsubsys | ||
1698 | *ph_subsys, u32 h_control, u16 index, u16 *pw_data); | ||
1699 | |||
1700 | u16 HPI_AESEBU__transmitter_query_format(const struct hpi_hsubsys *ph_subsys, | ||
1701 | const u32 h_aes_tx, const u32 index, u16 *pw_format); | ||
1702 | |||
1703 | u16 HPI_AESEBU__transmitter_set_format(const struct hpi_hsubsys *ph_subsys, | ||
1704 | u32 h_control, u16 output_format); | ||
1705 | |||
1706 | u16 HPI_AESEBU__transmitter_get_format(const struct hpi_hsubsys *ph_subsys, | ||
1707 | u32 h_control, u16 *pw_output_format); | ||
1708 | |||
1709 | /***********************/ | ||
1710 | /* multiplexer control */ | ||
1711 | /***********************/ | ||
1712 | u16 hpi_multiplexer_set_source(const struct hpi_hsubsys *ph_subsys, | ||
1713 | u32 h_control, u16 source_node_type, u16 source_node_index); | ||
1714 | |||
1715 | u16 hpi_multiplexer_get_source(const struct hpi_hsubsys *ph_subsys, | ||
1716 | u32 h_control, u16 *source_node_type, u16 *source_node_index); | ||
1717 | |||
1718 | u16 hpi_multiplexer_query_source(const struct hpi_hsubsys *ph_subsys, | ||
1719 | u32 h_control, u16 index, u16 *source_node_type, | ||
1720 | u16 *source_node_index); | ||
1721 | |||
1722 | /***************/ | ||
1723 | /* VOX control */ | ||
1724 | /***************/ | ||
1725 | u16 hpi_vox_set_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1726 | short an_gain0_01dB); | ||
1727 | |||
1728 | u16 hpi_vox_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1729 | short *an_gain0_01dB); | ||
1730 | |||
1731 | /*********************/ | ||
1732 | /* Bitstream control */ | ||
1733 | /*********************/ | ||
1734 | u16 hpi_bitstream_set_clock_edge(const struct hpi_hsubsys *ph_subsys, | ||
1735 | u32 h_control, u16 edge_type); | ||
1736 | |||
1737 | u16 hpi_bitstream_set_data_polarity(const struct hpi_hsubsys *ph_subsys, | ||
1738 | u32 h_control, u16 polarity); | ||
1739 | |||
1740 | u16 hpi_bitstream_get_activity(const struct hpi_hsubsys *ph_subsys, | ||
1741 | u32 h_control, u16 *pw_clk_activity, u16 *pw_data_activity); | ||
1742 | |||
1743 | /***********************/ | ||
1744 | /* SampleClock control */ | ||
1745 | /***********************/ | ||
1746 | |||
1747 | u16 hpi_sample_clock_query_source(const struct hpi_hsubsys *ph_subsys, | ||
1748 | const u32 h_clock, const u32 index, u16 *pw_source); | ||
1749 | |||
1750 | u16 hpi_sample_clock_set_source(const struct hpi_hsubsys *ph_subsys, | ||
1751 | u32 h_control, u16 source); | ||
1752 | |||
1753 | u16 hpi_sample_clock_get_source(const struct hpi_hsubsys *ph_subsys, | ||
1754 | u32 h_control, u16 *pw_source); | ||
1755 | |||
1756 | u16 hpi_sample_clock_query_source_index(const struct hpi_hsubsys *ph_subsys, | ||
1757 | const u32 h_clock, const u32 index, const u32 source, | ||
1758 | u16 *pw_source_index); | ||
1759 | |||
1760 | u16 hpi_sample_clock_set_source_index(const struct hpi_hsubsys *ph_subsys, | ||
1761 | u32 h_control, u16 source_index); | ||
1762 | |||
1763 | u16 hpi_sample_clock_get_source_index(const struct hpi_hsubsys *ph_subsys, | ||
1764 | u32 h_control, u16 *pw_source_index); | ||
1765 | |||
1766 | u16 hpi_sample_clock_get_sample_rate(const struct hpi_hsubsys *ph_subsys, | ||
1767 | u32 h_control, u32 *psample_rate); | ||
1768 | |||
1769 | u16 hpi_sample_clock_query_local_rate(const struct hpi_hsubsys *ph_subsys, | ||
1770 | const u32 h_clock, const u32 index, u32 *psource); | ||
1771 | |||
1772 | u16 hpi_sample_clock_set_local_rate(const struct hpi_hsubsys *ph_subsys, | ||
1773 | u32 h_control, u32 sample_rate); | ||
1774 | |||
1775 | u16 hpi_sample_clock_get_local_rate(const struct hpi_hsubsys *ph_subsys, | ||
1776 | u32 h_control, u32 *psample_rate); | ||
1777 | |||
1778 | u16 hpi_sample_clock_set_auto(const struct hpi_hsubsys *ph_subsys, | ||
1779 | u32 h_control, u32 enable); | ||
1780 | |||
1781 | u16 hpi_sample_clock_get_auto(const struct hpi_hsubsys *ph_subsys, | ||
1782 | u32 h_control, u32 *penable); | ||
1783 | |||
1784 | u16 hpi_sample_clock_set_local_rate_lock(const struct hpi_hsubsys *ph_subsys, | ||
1785 | u32 h_control, u32 lock); | ||
1786 | |||
1787 | u16 hpi_sample_clock_get_local_rate_lock(const struct hpi_hsubsys *ph_subsys, | ||
1788 | u32 h_control, u32 *plock); | ||
1789 | |||
1790 | /***********************/ | ||
1791 | /* Microphone control */ | ||
1792 | /***********************/ | ||
1793 | u16 hpi_microphone_set_phantom_power(const struct hpi_hsubsys *ph_subsys, | ||
1794 | u32 h_control, u16 on_off); | ||
1795 | |||
1796 | u16 hpi_microphone_get_phantom_power(const struct hpi_hsubsys *ph_subsys, | ||
1797 | u32 h_control, u16 *pw_on_off); | ||
1798 | |||
1799 | /******************************* | ||
1800 | Parametric Equalizer control | ||
1801 | *******************************/ | ||
1802 | u16 hpi_parametricEQ__get_info(const struct hpi_hsubsys *ph_subsys, | ||
1803 | u32 h_control, u16 *pw_number_of_bands, u16 *pw_enabled); | ||
1804 | |||
1805 | u16 hpi_parametricEQ__set_state(const struct hpi_hsubsys *ph_subsys, | ||
1806 | u32 h_control, u16 on_off); | ||
1807 | |||
1808 | u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys, | ||
1809 | u32 h_control, u16 index, u16 type, u32 frequency_hz, short q100, | ||
1810 | short gain0_01dB); | ||
1811 | |||
1812 | u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys, | ||
1813 | u32 h_control, u16 index, u16 *pn_type, u32 *pfrequency_hz, | ||
1814 | short *pnQ100, short *pn_gain0_01dB); | ||
1815 | |||
1816 | u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys, | ||
1817 | u32 h_control, u16 index, short coeffs[5] | ||
1818 | ); | ||
1819 | |||
1820 | /******************************* | ||
1821 | Compressor Expander control | ||
1822 | *******************************/ | ||
1823 | |||
1824 | u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1825 | u16 attack, u16 decay, short ratio100, short threshold0_01dB, | ||
1826 | short makeup_gain0_01dB); | ||
1827 | |||
1828 | u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1829 | u16 *pw_attack, u16 *pw_decay, short *pw_ratio100, | ||
1830 | short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB); | ||
1831 | |||
1832 | /******************************* | ||
1833 | Cobranet HMI control | ||
1834 | *******************************/ | ||
1835 | u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1836 | u32 hmi_address, u32 byte_count, u8 *pb_data); | ||
1837 | |||
1838 | u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1839 | u32 hmi_address, u32 max_byte_count, u32 *pbyte_count, u8 *pb_data); | ||
1840 | |||
1841 | u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys, | ||
1842 | u32 h_control, u32 *pstatus, u32 *preadable_size, | ||
1843 | u32 *pwriteable_size); | ||
1844 | |||
1845 | /*Read the current IP address | ||
1846 | */ | ||
1847 | u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys, | ||
1848 | u32 h_control, u32 *pi_paddress); | ||
1849 | |||
1850 | /* Write the current IP address | ||
1851 | */ | ||
1852 | u16 hpi_cobranet_setI_paddress(const struct hpi_hsubsys *ph_subsys, | ||
1853 | u32 h_control, u32 i_paddress); | ||
1854 | |||
1855 | /* Read the static IP address | ||
1856 | */ | ||
1857 | u16 hpi_cobranet_get_staticI_paddress(const struct hpi_hsubsys *ph_subsys, | ||
1858 | u32 h_control, u32 *pi_paddress); | ||
1859 | |||
1860 | /* Write the static IP address | ||
1861 | */ | ||
1862 | u16 hpi_cobranet_set_staticI_paddress(const struct hpi_hsubsys *ph_subsys, | ||
1863 | u32 h_control, u32 i_paddress); | ||
1864 | |||
1865 | /* Read the MAC address | ||
1866 | */ | ||
1867 | u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys, | ||
1868 | u32 h_control, u32 *pmAC_MS_bs, u32 *pmAC_LS_bs); | ||
1869 | |||
1870 | /******************************* | ||
1871 | Tone Detector control | ||
1872 | *******************************/ | ||
1873 | u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
1874 | u32 *state); | ||
1875 | |||
1876 | u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
1877 | u32 enable); | ||
1878 | |||
1879 | u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
1880 | u32 *enable); | ||
1881 | |||
1882 | u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, | ||
1883 | u32 hC, u32 event_enable); | ||
1884 | |||
1885 | u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, | ||
1886 | u32 hC, u32 *event_enable); | ||
1887 | |||
1888 | u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, | ||
1889 | u32 hC, int threshold); | ||
1890 | |||
1891 | u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, | ||
1892 | u32 hC, int *threshold); | ||
1893 | |||
1894 | u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys, | ||
1895 | u32 hC, u32 index, u32 *frequency); | ||
1896 | |||
1897 | /******************************* | ||
1898 | Silence Detector control | ||
1899 | *******************************/ | ||
1900 | u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys, | ||
1901 | u32 hC, u32 *state); | ||
1902 | |||
1903 | u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys, | ||
1904 | u32 hC, u32 enable); | ||
1905 | |||
1906 | u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys, | ||
1907 | u32 hC, u32 *enable); | ||
1908 | |||
1909 | u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, | ||
1910 | u32 hC, u32 event_enable); | ||
1911 | |||
1912 | u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, | ||
1913 | u32 hC, u32 *event_enable); | ||
1914 | |||
1915 | u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys, | ||
1916 | u32 hC, u32 delay); | ||
1917 | |||
1918 | u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys, | ||
1919 | u32 hC, u32 *delay); | ||
1920 | |||
1921 | u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, | ||
1922 | u32 hC, int threshold); | ||
1923 | |||
1924 | u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, | ||
1925 | u32 hC, int *threshold); | ||
1926 | |||
1927 | /******************************* | ||
1928 | Universal control | ||
1929 | *******************************/ | ||
1930 | u16 hpi_entity_find_next(struct hpi_entity *container_entity, | ||
1931 | enum e_entity_type type, enum e_entity_role role, int recursive_flag, | ||
1932 | struct hpi_entity **current_match); | ||
1933 | |||
1934 | u16 hpi_entity_copy_value_from(struct hpi_entity *entity, | ||
1935 | enum e_entity_type type, size_t item_count, void *value_dst_p); | ||
1936 | |||
1937 | u16 hpi_entity_unpack(struct hpi_entity *entity, enum e_entity_type *type, | ||
1938 | size_t *items, enum e_entity_role *role, void **value); | ||
1939 | |||
1940 | u16 hpi_entity_alloc_and_pack(const enum e_entity_type type, | ||
1941 | const size_t item_count, const enum e_entity_role role, void *value, | ||
1942 | struct hpi_entity **entity); | ||
1943 | |||
1944 | void hpi_entity_free(struct hpi_entity *entity); | ||
1945 | |||
1946 | u16 hpi_universal_info(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
1947 | struct hpi_entity **info); | ||
1948 | |||
1949 | u16 hpi_universal_get(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
1950 | struct hpi_entity **value); | ||
1951 | |||
1952 | u16 hpi_universal_set(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
1953 | struct hpi_entity *value); | ||
1954 | |||
1955 | /*/////////// */ | ||
1956 | /* DSP CLOCK */ | ||
1957 | /*/////////// */ | ||
1958 | u16 hpi_clock_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1959 | u32 *ph_dsp_clock); | ||
1960 | |||
1961 | u16 hpi_clock_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_clock, | ||
1962 | u16 hour, u16 minute, u16 second, u16 milli_second); | ||
1963 | |||
1964 | u16 hpi_clock_get_time(const struct hpi_hsubsys *ph_subsys, u32 h_clock, | ||
1965 | u16 *pw_hour, u16 *pw_minute, u16 *pw_second, u16 *pw_milli_second); | ||
1966 | |||
1967 | /*/////////// */ | ||
1968 | /* PROFILE */ | ||
1969 | /*/////////// */ | ||
1970 | u16 hpi_profile_open_all(const struct hpi_hsubsys *ph_subsys, | ||
1971 | u16 adapter_index, u16 profile_index, u32 *ph_profile, | ||
1972 | u16 *pw_max_profiles); | ||
1973 | |||
1974 | u16 hpi_profile_get(const struct hpi_hsubsys *ph_subsys, u32 h_profile, | ||
1975 | u16 index, u16 *pw_seconds, u32 *pmicro_seconds, u32 *pcall_count, | ||
1976 | u32 *pmax_micro_seconds, u32 *pmin_micro_seconds); | ||
1977 | |||
1978 | u16 hpi_profile_start_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile); | ||
1979 | |||
1980 | u16 hpi_profile_stop_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile); | ||
1981 | |||
1982 | u16 hpi_profile_get_name(const struct hpi_hsubsys *ph_subsys, u32 h_profile, | ||
1983 | u16 index, char *sz_profile_name, u16 profile_name_length); | ||
1984 | |||
1985 | u16 hpi_profile_get_utilization(const struct hpi_hsubsys *ph_subsys, | ||
1986 | u32 h_profile, u32 *putilization); | ||
1987 | |||
1988 | /*//////////////////// */ | ||
1989 | /* UTILITY functions */ | ||
1990 | |||
1991 | u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format, | ||
1992 | u32 sample_rate, u32 bit_rate, u32 attributes); | ||
1993 | |||
1994 | /* Until it's verified, this function is for Windows OSs only */ | ||
1995 | |||
1996 | #endif /*_H_HPI_ */ | ||
1997 | /* | ||
1998 | /////////////////////////////////////////////////////////////////////////////// | ||
1999 | // See CVS for history. Last complete set in rev 1.146 | ||
2000 | //////////////////////////////////////////////////////////////////////////////// | ||
2001 | */ | ||
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c new file mode 100644 index 00000000000..839ecb2e4b6 --- /dev/null +++ b/sound/pci/asihpi/hpi6000.c | |||
@@ -0,0 +1,1840 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Hardware Programming Interface (HPI) for AudioScience ASI6200 series adapters. | ||
20 | These PCI bus adapters are based on the TI C6711 DSP. | ||
21 | |||
22 | Exported functions: | ||
23 | void HPI_6000(struct hpi_message *phm, struct hpi_response *phr) | ||
24 | |||
25 | #defines | ||
26 | HIDE_PCI_ASSERTS to show the PCI asserts | ||
27 | PROFILE_DSP2 get profile data from DSP2 if present (instead of DSP 1) | ||
28 | |||
29 | (C) Copyright AudioScience Inc. 1998-2003 | ||
30 | *******************************************************************************/ | ||
31 | #define SOURCEFILE_NAME "hpi6000.c" | ||
32 | |||
33 | #include "hpi_internal.h" | ||
34 | #include "hpimsginit.h" | ||
35 | #include "hpidebug.h" | ||
36 | #include "hpi6000.h" | ||
37 | #include "hpidspcd.h" | ||
38 | #include "hpicmn.h" | ||
39 | |||
40 | #define HPI_HIF_BASE (0x00000200) /* start of C67xx internal RAM */ | ||
41 | #define HPI_HIF_ADDR(member) \ | ||
42 | (HPI_HIF_BASE + offsetof(struct hpi_hif_6000, member)) | ||
43 | #define HPI_HIF_ERROR_MASK 0x4000 | ||
44 | |||
45 | /* HPI6000 specific error codes */ | ||
46 | |||
47 | #define HPI6000_ERROR_BASE 900 | ||
48 | #define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT 901 | ||
49 | #define HPI6000_ERROR_MSG_RESP_SEND_MSG_ACK 902 | ||
50 | #define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK 903 | ||
51 | #define HPI6000_ERROR_MSG_GET_ADR 904 | ||
52 | #define HPI6000_ERROR_RESP_GET_ADR 905 | ||
53 | #define HPI6000_ERROR_MSG_RESP_BLOCKWRITE32 906 | ||
54 | #define HPI6000_ERROR_MSG_RESP_BLOCKREAD32 907 | ||
55 | #define HPI6000_ERROR_MSG_INVALID_DSP_INDEX 908 | ||
56 | #define HPI6000_ERROR_CONTROL_CACHE_PARAMS 909 | ||
57 | |||
58 | #define HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT 911 | ||
59 | #define HPI6000_ERROR_SEND_DATA_ACK 912 | ||
60 | #define HPI6000_ERROR_SEND_DATA_ADR 913 | ||
61 | #define HPI6000_ERROR_SEND_DATA_TIMEOUT 914 | ||
62 | #define HPI6000_ERROR_SEND_DATA_CMD 915 | ||
63 | #define HPI6000_ERROR_SEND_DATA_WRITE 916 | ||
64 | #define HPI6000_ERROR_SEND_DATA_IDLECMD 917 | ||
65 | #define HPI6000_ERROR_SEND_DATA_VERIFY 918 | ||
66 | |||
67 | #define HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT 921 | ||
68 | #define HPI6000_ERROR_GET_DATA_ACK 922 | ||
69 | #define HPI6000_ERROR_GET_DATA_CMD 923 | ||
70 | #define HPI6000_ERROR_GET_DATA_READ 924 | ||
71 | #define HPI6000_ERROR_GET_DATA_IDLECMD 925 | ||
72 | |||
73 | #define HPI6000_ERROR_CONTROL_CACHE_ADDRLEN 951 | ||
74 | #define HPI6000_ERROR_CONTROL_CACHE_READ 952 | ||
75 | #define HPI6000_ERROR_CONTROL_CACHE_FLUSH 953 | ||
76 | |||
77 | #define HPI6000_ERROR_MSG_RESP_GETRESPCMD 961 | ||
78 | #define HPI6000_ERROR_MSG_RESP_IDLECMD 962 | ||
79 | #define HPI6000_ERROR_MSG_RESP_BLOCKVERIFY32 963 | ||
80 | |||
81 | /* adapter init errors */ | ||
82 | #define HPI6000_ERROR_UNHANDLED_SUBSYS_ID 930 | ||
83 | |||
84 | /* can't access PCI2040 */ | ||
85 | #define HPI6000_ERROR_INIT_PCI2040 931 | ||
86 | /* can't access DSP HPI i/f */ | ||
87 | #define HPI6000_ERROR_INIT_DSPHPI 932 | ||
88 | /* can't access internal DSP memory */ | ||
89 | #define HPI6000_ERROR_INIT_DSPINTMEM 933 | ||
90 | /* can't access SDRAM - test#1 */ | ||
91 | #define HPI6000_ERROR_INIT_SDRAM1 934 | ||
92 | /* can't access SDRAM - test#2 */ | ||
93 | #define HPI6000_ERROR_INIT_SDRAM2 935 | ||
94 | |||
95 | #define HPI6000_ERROR_INIT_VERIFY 938 | ||
96 | |||
97 | #define HPI6000_ERROR_INIT_NOACK 939 | ||
98 | |||
99 | #define HPI6000_ERROR_INIT_PLDTEST1 941 | ||
100 | #define HPI6000_ERROR_INIT_PLDTEST2 942 | ||
101 | |||
102 | /* local defines */ | ||
103 | |||
104 | #define HIDE_PCI_ASSERTS | ||
105 | #define PROFILE_DSP2 | ||
106 | |||
107 | /* for PCI2040 i/f chip */ | ||
108 | /* HPI CSR registers */ | ||
109 | /* word offsets from CSR base */ | ||
110 | /* use when io addresses defined as u32 * */ | ||
111 | |||
112 | #define INTERRUPT_EVENT_SET 0 | ||
113 | #define INTERRUPT_EVENT_CLEAR 1 | ||
114 | #define INTERRUPT_MASK_SET 2 | ||
115 | #define INTERRUPT_MASK_CLEAR 3 | ||
116 | #define HPI_ERROR_REPORT 4 | ||
117 | #define HPI_RESET 5 | ||
118 | #define HPI_DATA_WIDTH 6 | ||
119 | |||
120 | #define MAX_DSPS 2 | ||
121 | /* HPI registers, spaced 8K bytes = 2K words apart */ | ||
122 | #define DSP_SPACING 0x800 | ||
123 | |||
124 | #define CONTROL 0x0000 | ||
125 | #define ADDRESS 0x0200 | ||
126 | #define DATA_AUTOINC 0x0400 | ||
127 | #define DATA 0x0600 | ||
128 | |||
129 | #define TIMEOUT 500000 | ||
130 | |||
131 | struct dsp_obj { | ||
132 | __iomem u32 *prHPI_control; | ||
133 | __iomem u32 *prHPI_address; | ||
134 | __iomem u32 *prHPI_data; | ||
135 | __iomem u32 *prHPI_data_auto_inc; | ||
136 | char c_dsp_rev; /*A, B */ | ||
137 | u32 control_cache_address_on_dsp; | ||
138 | u32 control_cache_length_on_dsp; | ||
139 | struct hpi_adapter_obj *pa_parent_adapter; | ||
140 | }; | ||
141 | |||
142 | struct hpi_hw_obj { | ||
143 | __iomem u32 *dw2040_HPICSR; | ||
144 | __iomem u32 *dw2040_HPIDSP; | ||
145 | |||
146 | u16 num_dsp; | ||
147 | struct dsp_obj ado[MAX_DSPS]; | ||
148 | |||
149 | u32 message_buffer_address_on_dsp; | ||
150 | u32 response_buffer_address_on_dsp; | ||
151 | u32 pCI2040HPI_error_count; | ||
152 | |||
153 | struct hpi_control_cache_single control_cache[HPI_NMIXER_CONTROLS]; | ||
154 | struct hpi_control_cache *p_cache; | ||
155 | }; | ||
156 | |||
157 | static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao, | ||
158 | u16 dsp_index, u32 hpi_address, u32 *source, u32 count); | ||
159 | static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao, | ||
160 | u16 dsp_index, u32 hpi_address, u32 *dest, u32 count); | ||
161 | |||
162 | static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, | ||
163 | u32 *pos_error_code); | ||
164 | static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao, | ||
165 | u16 read_or_write); | ||
166 | #define H6READ 1 | ||
167 | #define H6WRITE 0 | ||
168 | |||
169 | static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao, | ||
170 | struct hpi_message *phm); | ||
171 | static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao, | ||
172 | u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr); | ||
173 | |||
174 | static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, | ||
175 | struct hpi_response *phr); | ||
176 | |||
177 | static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index, | ||
178 | u32 ack_value); | ||
179 | |||
180 | static short hpi6000_send_host_command(struct hpi_adapter_obj *pao, | ||
181 | u16 dsp_index, u32 host_cmd); | ||
182 | |||
183 | static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo); | ||
184 | |||
185 | static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index, | ||
186 | struct hpi_message *phm, struct hpi_response *phr); | ||
187 | |||
188 | static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index, | ||
189 | struct hpi_message *phm, struct hpi_response *phr); | ||
190 | |||
191 | static void hpi_write_word(struct dsp_obj *pdo, u32 address, u32 data); | ||
192 | |||
193 | static u32 hpi_read_word(struct dsp_obj *pdo, u32 address); | ||
194 | |||
195 | static void hpi_write_block(struct dsp_obj *pdo, u32 address, u32 *pdata, | ||
196 | u32 length); | ||
197 | |||
198 | static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata, | ||
199 | u32 length); | ||
200 | |||
201 | static void subsys_create_adapter(struct hpi_message *phm, | ||
202 | struct hpi_response *phr); | ||
203 | |||
204 | static void subsys_delete_adapter(struct hpi_message *phm, | ||
205 | struct hpi_response *phr); | ||
206 | |||
207 | static void adapter_get_asserts(struct hpi_adapter_obj *pao, | ||
208 | struct hpi_message *phm, struct hpi_response *phr); | ||
209 | |||
210 | static short create_adapter_obj(struct hpi_adapter_obj *pao, | ||
211 | u32 *pos_error_code); | ||
212 | |||
213 | /* local globals */ | ||
214 | |||
215 | static u16 gw_pci_read_asserts; /* used to count PCI2040 errors */ | ||
216 | static u16 gw_pci_write_asserts; /* used to count PCI2040 errors */ | ||
217 | |||
218 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | ||
219 | { | ||
220 | |||
221 | switch (phm->function) { | ||
222 | case HPI_SUBSYS_OPEN: | ||
223 | case HPI_SUBSYS_CLOSE: | ||
224 | case HPI_SUBSYS_GET_INFO: | ||
225 | case HPI_SUBSYS_DRIVER_UNLOAD: | ||
226 | case HPI_SUBSYS_DRIVER_LOAD: | ||
227 | case HPI_SUBSYS_FIND_ADAPTERS: | ||
228 | /* messages that should not get here */ | ||
229 | phr->error = HPI_ERROR_UNIMPLEMENTED; | ||
230 | break; | ||
231 | case HPI_SUBSYS_CREATE_ADAPTER: | ||
232 | subsys_create_adapter(phm, phr); | ||
233 | break; | ||
234 | case HPI_SUBSYS_DELETE_ADAPTER: | ||
235 | subsys_delete_adapter(phm, phr); | ||
236 | break; | ||
237 | default: | ||
238 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
239 | break; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | static void control_message(struct hpi_adapter_obj *pao, | ||
244 | struct hpi_message *phm, struct hpi_response *phr) | ||
245 | { | ||
246 | |||
247 | switch (phm->function) { | ||
248 | case HPI_CONTROL_GET_STATE: | ||
249 | if (pao->has_control_cache) { | ||
250 | u16 err; | ||
251 | err = hpi6000_update_control_cache(pao, phm); | ||
252 | |||
253 | if (err) { | ||
254 | phr->error = err; | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | if (hpi_check_control_cache(((struct hpi_hw_obj *) | ||
259 | pao->priv)->p_cache, phm, | ||
260 | phr)) | ||
261 | break; | ||
262 | } | ||
263 | hw_message(pao, phm, phr); | ||
264 | break; | ||
265 | case HPI_CONTROL_GET_INFO: | ||
266 | hw_message(pao, phm, phr); | ||
267 | break; | ||
268 | case HPI_CONTROL_SET_STATE: | ||
269 | hw_message(pao, phm, phr); | ||
270 | hpi_sync_control_cache(((struct hpi_hw_obj *)pao->priv)-> | ||
271 | p_cache, phm, phr); | ||
272 | break; | ||
273 | default: | ||
274 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
275 | break; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | static void adapter_message(struct hpi_adapter_obj *pao, | ||
280 | struct hpi_message *phm, struct hpi_response *phr) | ||
281 | { | ||
282 | switch (phm->function) { | ||
283 | case HPI_ADAPTER_GET_INFO: | ||
284 | hw_message(pao, phm, phr); | ||
285 | break; | ||
286 | case HPI_ADAPTER_GET_ASSERT: | ||
287 | adapter_get_asserts(pao, phm, phr); | ||
288 | break; | ||
289 | case HPI_ADAPTER_OPEN: | ||
290 | case HPI_ADAPTER_CLOSE: | ||
291 | case HPI_ADAPTER_TEST_ASSERT: | ||
292 | case HPI_ADAPTER_SELFTEST: | ||
293 | case HPI_ADAPTER_GET_MODE: | ||
294 | case HPI_ADAPTER_SET_MODE: | ||
295 | case HPI_ADAPTER_FIND_OBJECT: | ||
296 | case HPI_ADAPTER_GET_PROPERTY: | ||
297 | case HPI_ADAPTER_SET_PROPERTY: | ||
298 | case HPI_ADAPTER_ENUM_PROPERTY: | ||
299 | hw_message(pao, phm, phr); | ||
300 | break; | ||
301 | default: | ||
302 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
303 | break; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static void outstream_message(struct hpi_adapter_obj *pao, | ||
308 | struct hpi_message *phm, struct hpi_response *phr) | ||
309 | { | ||
310 | switch (phm->function) { | ||
311 | case HPI_OSTREAM_HOSTBUFFER_ALLOC: | ||
312 | case HPI_OSTREAM_HOSTBUFFER_FREE: | ||
313 | /* Don't let these messages go to the HW function because | ||
314 | * they're called without allocating the spinlock. | ||
315 | * For the HPI6000 adapters the HW would return | ||
316 | * HPI_ERROR_INVALID_FUNC anyway. | ||
317 | */ | ||
318 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
319 | break; | ||
320 | default: | ||
321 | hw_message(pao, phm, phr); | ||
322 | return; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | static void instream_message(struct hpi_adapter_obj *pao, | ||
327 | struct hpi_message *phm, struct hpi_response *phr) | ||
328 | { | ||
329 | |||
330 | switch (phm->function) { | ||
331 | case HPI_ISTREAM_HOSTBUFFER_ALLOC: | ||
332 | case HPI_ISTREAM_HOSTBUFFER_FREE: | ||
333 | /* Don't let these messages go to the HW function because | ||
334 | * they're called without allocating the spinlock. | ||
335 | * For the HPI6000 adapters the HW would return | ||
336 | * HPI_ERROR_INVALID_FUNC anyway. | ||
337 | */ | ||
338 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
339 | break; | ||
340 | default: | ||
341 | hw_message(pao, phm, phr); | ||
342 | return; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | /************************************************************************/ | ||
347 | /** HPI_6000() | ||
348 | * Entry point from HPIMAN | ||
349 | * All calls to the HPI start here | ||
350 | */ | ||
351 | void HPI_6000(struct hpi_message *phm, struct hpi_response *phr) | ||
352 | { | ||
353 | struct hpi_adapter_obj *pao = NULL; | ||
354 | |||
355 | /* subsytem messages get executed by every HPI. */ | ||
356 | /* All other messages are ignored unless the adapter index matches */ | ||
357 | /* an adapter in the HPI */ | ||
358 | HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->object, phm->function); | ||
359 | |||
360 | /* if Dsp has crashed then do not communicate with it any more */ | ||
361 | if (phm->object != HPI_OBJ_SUBSYSTEM) { | ||
362 | pao = hpi_find_adapter(phm->adapter_index); | ||
363 | if (!pao) { | ||
364 | HPI_DEBUG_LOG(DEBUG, | ||
365 | " %d,%d refused, for another HPI?\n", | ||
366 | phm->object, phm->function); | ||
367 | return; | ||
368 | } | ||
369 | |||
370 | if (pao->dsp_crashed >= 10) { | ||
371 | hpi_init_response(phr, phm->object, phm->function, | ||
372 | HPI_ERROR_DSP_HARDWARE); | ||
373 | HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n", | ||
374 | phm->object, phm->function); | ||
375 | return; | ||
376 | } | ||
377 | } | ||
378 | /* Init default response including the size field */ | ||
379 | if (phm->function != HPI_SUBSYS_CREATE_ADAPTER) | ||
380 | hpi_init_response(phr, phm->object, phm->function, | ||
381 | HPI_ERROR_PROCESSING_MESSAGE); | ||
382 | |||
383 | switch (phm->type) { | ||
384 | case HPI_TYPE_MESSAGE: | ||
385 | switch (phm->object) { | ||
386 | case HPI_OBJ_SUBSYSTEM: | ||
387 | subsys_message(phm, phr); | ||
388 | break; | ||
389 | |||
390 | case HPI_OBJ_ADAPTER: | ||
391 | phr->size = | ||
392 | sizeof(struct hpi_response_header) + | ||
393 | sizeof(struct hpi_adapter_res); | ||
394 | adapter_message(pao, phm, phr); | ||
395 | break; | ||
396 | |||
397 | case HPI_OBJ_CONTROL: | ||
398 | control_message(pao, phm, phr); | ||
399 | break; | ||
400 | |||
401 | case HPI_OBJ_OSTREAM: | ||
402 | outstream_message(pao, phm, phr); | ||
403 | break; | ||
404 | |||
405 | case HPI_OBJ_ISTREAM: | ||
406 | instream_message(pao, phm, phr); | ||
407 | break; | ||
408 | |||
409 | default: | ||
410 | hw_message(pao, phm, phr); | ||
411 | break; | ||
412 | } | ||
413 | break; | ||
414 | |||
415 | default: | ||
416 | phr->error = HPI_ERROR_INVALID_TYPE; | ||
417 | break; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | /************************************************************************/ | ||
422 | /* SUBSYSTEM */ | ||
423 | |||
424 | /* create an adapter object and initialise it based on resource information | ||
425 | * passed in in the message | ||
426 | * NOTE - you cannot use this function AND the FindAdapters function at the | ||
427 | * same time, the application must use only one of them to get the adapters | ||
428 | */ | ||
429 | static void subsys_create_adapter(struct hpi_message *phm, | ||
430 | struct hpi_response *phr) | ||
431 | { | ||
432 | /* create temp adapter obj, because we don't know what index yet */ | ||
433 | struct hpi_adapter_obj ao; | ||
434 | struct hpi_adapter_obj *pao; | ||
435 | u32 os_error_code; | ||
436 | short error = 0; | ||
437 | u32 dsp_index = 0; | ||
438 | |||
439 | HPI_DEBUG_LOG(VERBOSE, "subsys_create_adapter\n"); | ||
440 | |||
441 | memset(&ao, 0, sizeof(ao)); | ||
442 | |||
443 | /* this HPI only creates adapters for TI/PCI2040 based devices */ | ||
444 | if (phm->u.s.resource.bus_type != HPI_BUS_PCI) | ||
445 | return; | ||
446 | if (phm->u.s.resource.r.pci->vendor_id != HPI_PCI_VENDOR_ID_TI) | ||
447 | return; | ||
448 | if (phm->u.s.resource.r.pci->device_id != HPI_PCI_DEV_ID_PCI2040) | ||
449 | return; | ||
450 | |||
451 | ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL); | ||
452 | if (!ao.priv) { | ||
453 | HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n"); | ||
454 | phr->error = HPI_ERROR_MEMORY_ALLOC; | ||
455 | return; | ||
456 | } | ||
457 | |||
458 | /* create the adapter object based on the resource information */ | ||
459 | /*? memcpy(&ao.Pci,&phm->u.s.Resource.r.Pci,sizeof(ao.Pci)); */ | ||
460 | ao.pci = *phm->u.s.resource.r.pci; | ||
461 | |||
462 | error = create_adapter_obj(&ao, &os_error_code); | ||
463 | if (!error) | ||
464 | error = hpi_add_adapter(&ao); | ||
465 | if (error) { | ||
466 | phr->u.s.data = os_error_code; | ||
467 | kfree(ao.priv); | ||
468 | phr->error = error; | ||
469 | return; | ||
470 | } | ||
471 | /* need to update paParentAdapter */ | ||
472 | pao = hpi_find_adapter(ao.index); | ||
473 | if (!pao) { | ||
474 | /* We just added this adapter, why can't we find it!? */ | ||
475 | HPI_DEBUG_LOG(ERROR, "lost adapter after boot\n"); | ||
476 | phr->error = 950; | ||
477 | return; | ||
478 | } | ||
479 | |||
480 | for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) { | ||
481 | struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; | ||
482 | phw->ado[dsp_index].pa_parent_adapter = pao; | ||
483 | } | ||
484 | |||
485 | phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type; | ||
486 | phr->u.s.adapter_index = ao.index; | ||
487 | phr->u.s.num_adapters++; | ||
488 | phr->error = 0; | ||
489 | } | ||
490 | |||
491 | static void subsys_delete_adapter(struct hpi_message *phm, | ||
492 | struct hpi_response *phr) | ||
493 | { | ||
494 | struct hpi_adapter_obj *pao = NULL; | ||
495 | struct hpi_hw_obj *phw; | ||
496 | |||
497 | pao = hpi_find_adapter(phm->adapter_index); | ||
498 | if (!pao) | ||
499 | return; | ||
500 | |||
501 | phw = (struct hpi_hw_obj *)pao->priv; | ||
502 | |||
503 | if (pao->has_control_cache) | ||
504 | hpi_free_control_cache(phw->p_cache); | ||
505 | |||
506 | hpi_delete_adapter(pao); | ||
507 | kfree(phw); | ||
508 | |||
509 | phr->error = 0; | ||
510 | } | ||
511 | |||
512 | /* this routine is called from SubSysFindAdapter and SubSysCreateAdapter */ | ||
513 | static short create_adapter_obj(struct hpi_adapter_obj *pao, | ||
514 | u32 *pos_error_code) | ||
515 | { | ||
516 | short boot_error = 0; | ||
517 | u32 dsp_index = 0; | ||
518 | u32 control_cache_size = 0; | ||
519 | u32 control_cache_count = 0; | ||
520 | struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; | ||
521 | |||
522 | /* init error reporting */ | ||
523 | pao->dsp_crashed = 0; | ||
524 | |||
525 | /* The PCI2040 has the following address map */ | ||
526 | /* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */ | ||
527 | /* BAR1 - 32K = HPI registers on DSP */ | ||
528 | phw->dw2040_HPICSR = pao->pci.ap_mem_base[0]; | ||
529 | phw->dw2040_HPIDSP = pao->pci.ap_mem_base[1]; | ||
530 | HPI_DEBUG_LOG(VERBOSE, "csr %p, dsp %p\n", phw->dw2040_HPICSR, | ||
531 | phw->dw2040_HPIDSP); | ||
532 | |||
533 | /* set addresses for the possible DSP HPI interfaces */ | ||
534 | for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) { | ||
535 | phw->ado[dsp_index].prHPI_control = | ||
536 | phw->dw2040_HPIDSP + (CONTROL + | ||
537 | DSP_SPACING * dsp_index); | ||
538 | |||
539 | phw->ado[dsp_index].prHPI_address = | ||
540 | phw->dw2040_HPIDSP + (ADDRESS + | ||
541 | DSP_SPACING * dsp_index); | ||
542 | phw->ado[dsp_index].prHPI_data = | ||
543 | phw->dw2040_HPIDSP + (DATA + DSP_SPACING * dsp_index); | ||
544 | |||
545 | phw->ado[dsp_index].prHPI_data_auto_inc = | ||
546 | phw->dw2040_HPIDSP + (DATA_AUTOINC + | ||
547 | DSP_SPACING * dsp_index); | ||
548 | |||
549 | HPI_DEBUG_LOG(VERBOSE, "ctl %p, adr %p, dat %p, dat++ %p\n", | ||
550 | phw->ado[dsp_index].prHPI_control, | ||
551 | phw->ado[dsp_index].prHPI_address, | ||
552 | phw->ado[dsp_index].prHPI_data, | ||
553 | phw->ado[dsp_index].prHPI_data_auto_inc); | ||
554 | |||
555 | phw->ado[dsp_index].pa_parent_adapter = pao; | ||
556 | } | ||
557 | |||
558 | phw->pCI2040HPI_error_count = 0; | ||
559 | pao->has_control_cache = 0; | ||
560 | |||
561 | /* Set the default number of DSPs on this card */ | ||
562 | /* This is (conditionally) adjusted after bootloading */ | ||
563 | /* of the first DSP in the bootload section. */ | ||
564 | phw->num_dsp = 1; | ||
565 | |||
566 | boot_error = hpi6000_adapter_boot_load_dsp(pao, pos_error_code); | ||
567 | if (boot_error) | ||
568 | return boot_error; | ||
569 | |||
570 | HPI_DEBUG_LOG(INFO, "bootload DSP OK\n"); | ||
571 | |||
572 | phw->message_buffer_address_on_dsp = 0L; | ||
573 | phw->response_buffer_address_on_dsp = 0L; | ||
574 | |||
575 | /* get info about the adapter by asking the adapter */ | ||
576 | /* send a HPI_ADAPTER_GET_INFO message */ | ||
577 | { | ||
578 | struct hpi_message hM; | ||
579 | struct hpi_response hR0; /* response from DSP 0 */ | ||
580 | struct hpi_response hR1; /* response from DSP 1 */ | ||
581 | u16 error = 0; | ||
582 | |||
583 | HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n"); | ||
584 | memset(&hM, 0, sizeof(hM)); | ||
585 | hM.type = HPI_TYPE_MESSAGE; | ||
586 | hM.size = sizeof(struct hpi_message); | ||
587 | hM.object = HPI_OBJ_ADAPTER; | ||
588 | hM.function = HPI_ADAPTER_GET_INFO; | ||
589 | hM.adapter_index = 0; | ||
590 | memset(&hR0, 0, sizeof(hR0)); | ||
591 | memset(&hR1, 0, sizeof(hR1)); | ||
592 | hR0.size = sizeof(hR0); | ||
593 | hR1.size = sizeof(hR1); | ||
594 | |||
595 | error = hpi6000_message_response_sequence(pao, 0, &hM, &hR0); | ||
596 | if (hR0.error) { | ||
597 | HPI_DEBUG_LOG(DEBUG, "message error %d\n", hR0.error); | ||
598 | return hR0.error; | ||
599 | } | ||
600 | if (phw->num_dsp == 2) { | ||
601 | error = hpi6000_message_response_sequence(pao, 1, &hM, | ||
602 | &hR1); | ||
603 | if (error) | ||
604 | return error; | ||
605 | } | ||
606 | pao->adapter_type = hR0.u.a.adapter_type; | ||
607 | pao->index = hR0.u.a.adapter_index; | ||
608 | } | ||
609 | |||
610 | memset(&phw->control_cache[0], 0, | ||
611 | sizeof(struct hpi_control_cache_single) * | ||
612 | HPI_NMIXER_CONTROLS); | ||
613 | /* Read the control cache length to figure out if it is turned on */ | ||
614 | control_cache_size = | ||
615 | hpi_read_word(&phw->ado[0], | ||
616 | HPI_HIF_ADDR(control_cache_size_in_bytes)); | ||
617 | if (control_cache_size) { | ||
618 | control_cache_count = | ||
619 | hpi_read_word(&phw->ado[0], | ||
620 | HPI_HIF_ADDR(control_cache_count)); | ||
621 | pao->has_control_cache = 1; | ||
622 | |||
623 | phw->p_cache = | ||
624 | hpi_alloc_control_cache(control_cache_count, | ||
625 | control_cache_size, (struct hpi_control_cache_info *) | ||
626 | &phw->control_cache[0] | ||
627 | ); | ||
628 | } else | ||
629 | pao->has_control_cache = 0; | ||
630 | |||
631 | HPI_DEBUG_LOG(DEBUG, "get adapter info ASI%04X index %d\n", | ||
632 | pao->adapter_type, pao->index); | ||
633 | pao->open = 0; /* upon creation the adapter is closed */ | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | /************************************************************************/ | ||
638 | /* ADAPTER */ | ||
639 | |||
640 | static void adapter_get_asserts(struct hpi_adapter_obj *pao, | ||
641 | struct hpi_message *phm, struct hpi_response *phr) | ||
642 | { | ||
643 | #ifndef HIDE_PCI_ASSERTS | ||
644 | /* if we have PCI2040 asserts then collect them */ | ||
645 | if ((gw_pci_read_asserts > 0) || (gw_pci_write_asserts > 0)) { | ||
646 | phr->u.a.serial_number = | ||
647 | gw_pci_read_asserts * 100 + gw_pci_write_asserts; | ||
648 | phr->u.a.adapter_index = 1; /* assert count */ | ||
649 | phr->u.a.adapter_type = -1; /* "dsp index" */ | ||
650 | strcpy(phr->u.a.sz_adapter_assert, "PCI2040 error"); | ||
651 | gw_pci_read_asserts = 0; | ||
652 | gw_pci_write_asserts = 0; | ||
653 | phr->error = 0; | ||
654 | } else | ||
655 | #endif | ||
656 | hw_message(pao, phm, phr); /*get DSP asserts */ | ||
657 | |||
658 | return; | ||
659 | } | ||
660 | |||
661 | /************************************************************************/ | ||
662 | /* LOW-LEVEL */ | ||
663 | |||
664 | static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, | ||
665 | u32 *pos_error_code) | ||
666 | { | ||
667 | struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; | ||
668 | short error; | ||
669 | u32 timeout; | ||
670 | u32 read = 0; | ||
671 | u32 i = 0; | ||
672 | u32 data = 0; | ||
673 | u32 j = 0; | ||
674 | u32 test_addr = 0x80000000; | ||
675 | u32 test_data = 0x00000001; | ||
676 | u32 dw2040_reset = 0; | ||
677 | u32 dsp_index = 0; | ||
678 | u32 endian = 0; | ||
679 | u32 adapter_info = 0; | ||
680 | u32 delay = 0; | ||
681 | |||
682 | struct dsp_code dsp_code; | ||
683 | u16 boot_load_family = 0; | ||
684 | |||
685 | /* NOTE don't use wAdapterType in this routine. It is not setup yet */ | ||
686 | |||
687 | switch (pao->pci.subsys_device_id) { | ||
688 | case 0x5100: | ||
689 | case 0x5110: /* ASI5100 revB or higher with C6711D */ | ||
690 | case 0x6100: | ||
691 | case 0x6200: | ||
692 | boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200); | ||
693 | break; | ||
694 | case 0x8800: | ||
695 | boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x8800); | ||
696 | break; | ||
697 | default: | ||
698 | return HPI6000_ERROR_UNHANDLED_SUBSYS_ID; | ||
699 | } | ||
700 | |||
701 | /* reset all DSPs, indicate two DSPs are present | ||
702 | * set RST3-=1 to disconnect HAD8 to set DSP in little endian mode | ||
703 | */ | ||
704 | endian = 0; | ||
705 | dw2040_reset = 0x0003000F; | ||
706 | iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); | ||
707 | |||
708 | /* read back register to make sure PCI2040 chip is functioning | ||
709 | * note that bits 4..15 are read-only and so should always return zero, | ||
710 | * even though we wrote 1 to them | ||
711 | */ | ||
712 | for (i = 0; i < 1000; i++) | ||
713 | delay = ioread32(phw->dw2040_HPICSR + HPI_RESET); | ||
714 | if (delay != dw2040_reset) { | ||
715 | HPI_DEBUG_LOG(ERROR, "INIT_PCI2040 %x %x\n", dw2040_reset, | ||
716 | delay); | ||
717 | return HPI6000_ERROR_INIT_PCI2040; | ||
718 | } | ||
719 | |||
720 | /* Indicate that DSP#0,1 is a C6X */ | ||
721 | iowrite32(0x00000003, phw->dw2040_HPICSR + HPI_DATA_WIDTH); | ||
722 | /* set Bit30 and 29 - which will prevent Target aborts from being | ||
723 | * issued upon HPI or GP error | ||
724 | */ | ||
725 | iowrite32(0x60000000, phw->dw2040_HPICSR + INTERRUPT_MASK_SET); | ||
726 | |||
727 | /* isolate DSP HAD8 line from PCI2040 so that | ||
728 | * Little endian can be set by pullup | ||
729 | */ | ||
730 | dw2040_reset = dw2040_reset & (~(endian << 3)); | ||
731 | iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); | ||
732 | |||
733 | phw->ado[0].c_dsp_rev = 'B'; /* revB */ | ||
734 | phw->ado[1].c_dsp_rev = 'B'; /* revB */ | ||
735 | |||
736 | /*Take both DSPs out of reset, setting HAD8 to the correct Endian */ | ||
737 | dw2040_reset = dw2040_reset & (~0x00000001); /* start DSP 0 */ | ||
738 | iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); | ||
739 | dw2040_reset = dw2040_reset & (~0x00000002); /* start DSP 1 */ | ||
740 | iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); | ||
741 | |||
742 | /* set HAD8 back to PCI2040, now that DSP set to little endian mode */ | ||
743 | dw2040_reset = dw2040_reset & (~0x00000008); | ||
744 | iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); | ||
745 | /*delay to allow DSP to get going */ | ||
746 | for (i = 0; i < 100; i++) | ||
747 | delay = ioread32(phw->dw2040_HPICSR + HPI_RESET); | ||
748 | |||
749 | /* loop through all DSPs, downloading DSP code */ | ||
750 | for (dsp_index = 0; dsp_index < phw->num_dsp; dsp_index++) { | ||
751 | struct dsp_obj *pdo = &phw->ado[dsp_index]; | ||
752 | |||
753 | /* configure DSP so that we download code into the SRAM */ | ||
754 | /* set control reg for little endian, HWOB=1 */ | ||
755 | iowrite32(0x00010001, pdo->prHPI_control); | ||
756 | |||
757 | /* test access to the HPI address register (HPIA) */ | ||
758 | test_data = 0x00000001; | ||
759 | for (j = 0; j < 32; j++) { | ||
760 | iowrite32(test_data, pdo->prHPI_address); | ||
761 | data = ioread32(pdo->prHPI_address); | ||
762 | if (data != test_data) { | ||
763 | HPI_DEBUG_LOG(ERROR, "INIT_DSPHPI %x %x %x\n", | ||
764 | test_data, data, dsp_index); | ||
765 | return HPI6000_ERROR_INIT_DSPHPI; | ||
766 | } | ||
767 | test_data = test_data << 1; | ||
768 | } | ||
769 | |||
770 | /* if C6713 the setup PLL to generate 225MHz from 25MHz. | ||
771 | * Since the PLLDIV1 read is sometimes wrong, even on a C6713, | ||
772 | * we're going to do this unconditionally | ||
773 | */ | ||
774 | /* PLLDIV1 should have a value of 8000 after reset */ | ||
775 | /* | ||
776 | if (HpiReadWord(pdo,0x01B7C118) == 0x8000) | ||
777 | */ | ||
778 | { | ||
779 | /* C6713 datasheet says we cannot program PLL from HPI, | ||
780 | * and indeed if we try to set the PLL multiply from the | ||
781 | * HPI, the PLL does not seem to lock, | ||
782 | * so we enable the PLL and use the default of x 7 | ||
783 | */ | ||
784 | /* bypass PLL */ | ||
785 | hpi_write_word(pdo, 0x01B7C100, 0x0000); | ||
786 | for (i = 0; i < 100; i++) | ||
787 | delay = ioread32(phw->dw2040_HPICSR + | ||
788 | HPI_RESET); | ||
789 | |||
790 | /* ** use default of PLL x7 ** */ | ||
791 | /* EMIF = 225/3=75MHz */ | ||
792 | hpi_write_word(pdo, 0x01B7C120, 0x8002); | ||
793 | /* peri = 225/2 */ | ||
794 | hpi_write_word(pdo, 0x01B7C11C, 0x8001); | ||
795 | /* cpu = 225/1 */ | ||
796 | hpi_write_word(pdo, 0x01B7C118, 0x8000); | ||
797 | /* ~200us delay */ | ||
798 | for (i = 0; i < 2000; i++) | ||
799 | delay = ioread32(phw->dw2040_HPICSR + | ||
800 | HPI_RESET); | ||
801 | /* PLL not bypassed */ | ||
802 | hpi_write_word(pdo, 0x01B7C100, 0x0001); | ||
803 | /* ~200us delay */ | ||
804 | for (i = 0; i < 2000; i++) | ||
805 | delay = ioread32(phw->dw2040_HPICSR + | ||
806 | HPI_RESET); | ||
807 | } | ||
808 | |||
809 | /* test r/w to internal DSP memory | ||
810 | * C6711 has L2 cache mapped to 0x0 when reset | ||
811 | * | ||
812 | * revB - because of bug 3.0.1 last HPI read | ||
813 | * (before HPI address issued) must be non-autoinc | ||
814 | */ | ||
815 | /* test each bit in the 32bit word */ | ||
816 | for (i = 0; i < 100; i++) { | ||
817 | test_addr = 0x00000000; | ||
818 | test_data = 0x00000001; | ||
819 | for (j = 0; j < 32; j++) { | ||
820 | hpi_write_word(pdo, test_addr + i, test_data); | ||
821 | data = hpi_read_word(pdo, test_addr + i); | ||
822 | if (data != test_data) { | ||
823 | HPI_DEBUG_LOG(ERROR, | ||
824 | "DSP mem %x %x %x %x\n", | ||
825 | test_addr + i, test_data, | ||
826 | data, dsp_index); | ||
827 | |||
828 | return HPI6000_ERROR_INIT_DSPINTMEM; | ||
829 | } | ||
830 | test_data = test_data << 1; | ||
831 | } | ||
832 | } | ||
833 | |||
834 | /* memory map of ASI6200 | ||
835 | 00000000-0000FFFF 16Kx32 internal program | ||
836 | 01800000-019FFFFF Internal peripheral | ||
837 | 80000000-807FFFFF CE0 2Mx32 SDRAM running @ 100MHz | ||
838 | 90000000-9000FFFF CE1 Async peripherals: | ||
839 | |||
840 | EMIF config | ||
841 | ------------ | ||
842 | Global EMIF control | ||
843 | 0 - | ||
844 | 1 - | ||
845 | 2 - | ||
846 | 3 CLK2EN = 1 CLKOUT2 enabled | ||
847 | 4 CLK1EN = 0 CLKOUT1 disabled | ||
848 | 5 EKEN = 1 <--!! C6713 specific, enables ECLKOUT | ||
849 | 6 - | ||
850 | 7 NOHOLD = 1 external HOLD disabled | ||
851 | 8 HOLDA = 0 HOLDA output is low | ||
852 | 9 HOLD = 0 HOLD input is low | ||
853 | 10 ARDY = 1 ARDY input is high | ||
854 | 11 BUSREQ = 0 BUSREQ output is low | ||
855 | 12,13 Reserved = 1 | ||
856 | */ | ||
857 | hpi_write_word(pdo, 0x01800000, 0x34A8); | ||
858 | |||
859 | /* EMIF CE0 setup - 2Mx32 Sync DRAM | ||
860 | 31..28 Wr setup | ||
861 | 27..22 Wr strobe | ||
862 | 21..20 Wr hold | ||
863 | 19..16 Rd setup | ||
864 | 15..14 - | ||
865 | 13..8 Rd strobe | ||
866 | 7..4 MTYPE 0011 Sync DRAM 32bits | ||
867 | 3 Wr hold MSB | ||
868 | 2..0 Rd hold | ||
869 | */ | ||
870 | hpi_write_word(pdo, 0x01800008, 0x00000030); | ||
871 | |||
872 | /* EMIF SDRAM Extension | ||
873 | 31-21 0 | ||
874 | 20 WR2RD = 0 | ||
875 | 19-18 WR2DEAC = 1 | ||
876 | 17 WR2WR = 0 | ||
877 | 16-15 R2WDQM = 2 | ||
878 | 14-12 RD2WR = 4 | ||
879 | 11-10 RD2DEAC = 1 | ||
880 | 9 RD2RD = 1 | ||
881 | 8-7 THZP = 10b | ||
882 | 6-5 TWR = 2-1 = 01b (tWR = 10ns) | ||
883 | 4 TRRD = 0b = 2 ECLK (tRRD = 14ns) | ||
884 | 3-1 TRAS = 5-1 = 100b (Tras=42ns = 5 ECLK) | ||
885 | 1 CAS latency = 3 ECLK | ||
886 | (for Micron 2M32-7 operating at 100Mhz) | ||
887 | */ | ||
888 | |||
889 | /* need to use this else DSP code crashes */ | ||
890 | hpi_write_word(pdo, 0x01800020, 0x001BDF29); | ||
891 | |||
892 | /* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank) | ||
893 | 31 - - | ||
894 | 30 SDBSZ 1 4 bank | ||
895 | 29..28 SDRSZ 00 11 row address pins | ||
896 | 27..26 SDCSZ 01 8 column address pins | ||
897 | 25 RFEN 1 refersh enabled | ||
898 | 24 INIT 1 init SDRAM | ||
899 | 23..20 TRCD 0001 | ||
900 | 19..16 TRP 0001 | ||
901 | 15..12 TRC 0110 | ||
902 | 11..0 - - | ||
903 | */ | ||
904 | /* need to use this else DSP code crashes */ | ||
905 | hpi_write_word(pdo, 0x01800018, 0x47117000); | ||
906 | |||
907 | /* EMIF SDRAM Refresh Timing */ | ||
908 | hpi_write_word(pdo, 0x0180001C, 0x00000410); | ||
909 | |||
910 | /*MIF CE1 setup - Async peripherals | ||
911 | @100MHz bus speed, each cycle is 10ns, | ||
912 | 31..28 Wr setup = 1 | ||
913 | 27..22 Wr strobe = 3 30ns | ||
914 | 21..20 Wr hold = 1 | ||
915 | 19..16 Rd setup =1 | ||
916 | 15..14 Ta = 2 | ||
917 | 13..8 Rd strobe = 3 30ns | ||
918 | 7..4 MTYPE 0010 Async 32bits | ||
919 | 3 Wr hold MSB =0 | ||
920 | 2..0 Rd hold = 1 | ||
921 | */ | ||
922 | { | ||
923 | u32 cE1 = | ||
924 | (1L << 28) | (3L << 22) | (1L << 20) | (1L << | ||
925 | 16) | (2L << 14) | (3L << 8) | (2L << 4) | 1L; | ||
926 | hpi_write_word(pdo, 0x01800004, cE1); | ||
927 | } | ||
928 | |||
929 | /* delay a little to allow SDRAM and DSP to "get going" */ | ||
930 | |||
931 | for (i = 0; i < 1000; i++) | ||
932 | delay = ioread32(phw->dw2040_HPICSR + HPI_RESET); | ||
933 | |||
934 | /* test access to SDRAM */ | ||
935 | { | ||
936 | test_addr = 0x80000000; | ||
937 | test_data = 0x00000001; | ||
938 | /* test each bit in the 32bit word */ | ||
939 | for (j = 0; j < 32; j++) { | ||
940 | hpi_write_word(pdo, test_addr, test_data); | ||
941 | data = hpi_read_word(pdo, test_addr); | ||
942 | if (data != test_data) { | ||
943 | HPI_DEBUG_LOG(ERROR, | ||
944 | "DSP dram %x %x %x %x\n", | ||
945 | test_addr, test_data, data, | ||
946 | dsp_index); | ||
947 | |||
948 | return HPI6000_ERROR_INIT_SDRAM1; | ||
949 | } | ||
950 | test_data = test_data << 1; | ||
951 | } | ||
952 | /* test every Nth address in the DRAM */ | ||
953 | #define DRAM_SIZE_WORDS 0x200000 /*2_mx32 */ | ||
954 | #define DRAM_INC 1024 | ||
955 | test_addr = 0x80000000; | ||
956 | test_data = 0x0; | ||
957 | for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) { | ||
958 | hpi_write_word(pdo, test_addr + i, test_data); | ||
959 | test_data++; | ||
960 | } | ||
961 | test_addr = 0x80000000; | ||
962 | test_data = 0x0; | ||
963 | for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) { | ||
964 | data = hpi_read_word(pdo, test_addr + i); | ||
965 | if (data != test_data) { | ||
966 | HPI_DEBUG_LOG(ERROR, | ||
967 | "DSP dram %x %x %x %x\n", | ||
968 | test_addr + i, test_data, | ||
969 | data, dsp_index); | ||
970 | return HPI6000_ERROR_INIT_SDRAM2; | ||
971 | } | ||
972 | test_data++; | ||
973 | } | ||
974 | |||
975 | } | ||
976 | |||
977 | /* write the DSP code down into the DSPs memory */ | ||
978 | /*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */ | ||
979 | dsp_code.ps_dev = pao->pci.p_os_data; | ||
980 | |||
981 | error = hpi_dsp_code_open(boot_load_family, &dsp_code, | ||
982 | pos_error_code); | ||
983 | |||
984 | if (error) | ||
985 | return error; | ||
986 | |||
987 | while (1) { | ||
988 | u32 length; | ||
989 | u32 address; | ||
990 | u32 type; | ||
991 | u32 *pcode; | ||
992 | |||
993 | error = hpi_dsp_code_read_word(&dsp_code, &length); | ||
994 | if (error) | ||
995 | break; | ||
996 | if (length == 0xFFFFFFFF) | ||
997 | break; /* end of code */ | ||
998 | |||
999 | error = hpi_dsp_code_read_word(&dsp_code, &address); | ||
1000 | if (error) | ||
1001 | break; | ||
1002 | error = hpi_dsp_code_read_word(&dsp_code, &type); | ||
1003 | if (error) | ||
1004 | break; | ||
1005 | error = hpi_dsp_code_read_block(length, &dsp_code, | ||
1006 | &pcode); | ||
1007 | if (error) | ||
1008 | break; | ||
1009 | error = hpi6000_dsp_block_write32(pao, (u16)dsp_index, | ||
1010 | address, pcode, length); | ||
1011 | if (error) | ||
1012 | break; | ||
1013 | } | ||
1014 | |||
1015 | if (error) { | ||
1016 | hpi_dsp_code_close(&dsp_code); | ||
1017 | return error; | ||
1018 | } | ||
1019 | /* verify that code was written correctly */ | ||
1020 | /* this time through, assume no errors in DSP code file/array */ | ||
1021 | hpi_dsp_code_rewind(&dsp_code); | ||
1022 | while (1) { | ||
1023 | u32 length; | ||
1024 | u32 address; | ||
1025 | u32 type; | ||
1026 | u32 *pcode; | ||
1027 | |||
1028 | hpi_dsp_code_read_word(&dsp_code, &length); | ||
1029 | if (length == 0xFFFFFFFF) | ||
1030 | break; /* end of code */ | ||
1031 | |||
1032 | hpi_dsp_code_read_word(&dsp_code, &address); | ||
1033 | hpi_dsp_code_read_word(&dsp_code, &type); | ||
1034 | hpi_dsp_code_read_block(length, &dsp_code, &pcode); | ||
1035 | |||
1036 | for (i = 0; i < length; i++) { | ||
1037 | data = hpi_read_word(pdo, address); | ||
1038 | if (data != *pcode) { | ||
1039 | error = HPI6000_ERROR_INIT_VERIFY; | ||
1040 | HPI_DEBUG_LOG(ERROR, | ||
1041 | "DSP verify %x %x %x %x\n", | ||
1042 | address, *pcode, data, | ||
1043 | dsp_index); | ||
1044 | break; | ||
1045 | } | ||
1046 | pcode++; | ||
1047 | address += 4; | ||
1048 | } | ||
1049 | if (error) | ||
1050 | break; | ||
1051 | } | ||
1052 | hpi_dsp_code_close(&dsp_code); | ||
1053 | if (error) | ||
1054 | return error; | ||
1055 | |||
1056 | /* zero out the hostmailbox */ | ||
1057 | { | ||
1058 | u32 address = HPI_HIF_ADDR(host_cmd); | ||
1059 | for (i = 0; i < 4; i++) { | ||
1060 | hpi_write_word(pdo, address, 0); | ||
1061 | address += 4; | ||
1062 | } | ||
1063 | } | ||
1064 | /* write the DSP number into the hostmailbox */ | ||
1065 | /* structure before starting the DSP */ | ||
1066 | hpi_write_word(pdo, HPI_HIF_ADDR(dsp_number), dsp_index); | ||
1067 | |||
1068 | /* write the DSP adapter Info into the */ | ||
1069 | /* hostmailbox before starting the DSP */ | ||
1070 | if (dsp_index > 0) | ||
1071 | hpi_write_word(pdo, HPI_HIF_ADDR(adapter_info), | ||
1072 | adapter_info); | ||
1073 | |||
1074 | /* step 3. Start code by sending interrupt */ | ||
1075 | iowrite32(0x00030003, pdo->prHPI_control); | ||
1076 | for (i = 0; i < 10000; i++) | ||
1077 | delay = ioread32(phw->dw2040_HPICSR + HPI_RESET); | ||
1078 | |||
1079 | /* wait for a non-zero value in hostcmd - | ||
1080 | * indicating initialization is complete | ||
1081 | * | ||
1082 | * Init could take a while if DSP checks SDRAM memory | ||
1083 | * Was 200000. Increased to 2000000 for ASI8801 so we | ||
1084 | * don't get 938 errors. | ||
1085 | */ | ||
1086 | timeout = 2000000; | ||
1087 | while (timeout) { | ||
1088 | do { | ||
1089 | read = hpi_read_word(pdo, | ||
1090 | HPI_HIF_ADDR(host_cmd)); | ||
1091 | } while (--timeout | ||
1092 | && hpi6000_check_PCI2040_error_flag(pao, | ||
1093 | H6READ)); | ||
1094 | |||
1095 | if (read) | ||
1096 | break; | ||
1097 | /* The following is a workaround for bug #94: | ||
1098 | * Bluescreen on install and subsequent boots on a | ||
1099 | * DELL PowerEdge 600SC PC with 1.8GHz P4 and | ||
1100 | * ServerWorks chipset. Without this delay the system | ||
1101 | * locks up with a bluescreen (NOT GPF or pagefault). | ||
1102 | */ | ||
1103 | else | ||
1104 | hpios_delay_micro_seconds(1000); | ||
1105 | } | ||
1106 | if (timeout == 0) | ||
1107 | return HPI6000_ERROR_INIT_NOACK; | ||
1108 | |||
1109 | /* read the DSP adapter Info from the */ | ||
1110 | /* hostmailbox structure after starting the DSP */ | ||
1111 | if (dsp_index == 0) { | ||
1112 | /*u32 dwTestData=0; */ | ||
1113 | u32 mask = 0; | ||
1114 | |||
1115 | adapter_info = | ||
1116 | hpi_read_word(pdo, | ||
1117 | HPI_HIF_ADDR(adapter_info)); | ||
1118 | if (HPI_ADAPTER_FAMILY_ASI | ||
1119 | (HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER | ||
1120 | (adapter_info)) == | ||
1121 | HPI_ADAPTER_FAMILY_ASI(0x6200)) | ||
1122 | /* all 6200 cards have this many DSPs */ | ||
1123 | phw->num_dsp = 2; | ||
1124 | |||
1125 | /* test that the PLD is programmed */ | ||
1126 | /* and we can read/write 24bits */ | ||
1127 | #define PLD_BASE_ADDRESS 0x90000000L /*for ASI6100/6200/8800 */ | ||
1128 | |||
1129 | switch (boot_load_family) { | ||
1130 | case HPI_ADAPTER_FAMILY_ASI(0x6200): | ||
1131 | /* ASI6100/6200 has 24bit path to FPGA */ | ||
1132 | mask = 0xFFFFFF00L; | ||
1133 | /* ASI5100 uses AX6 code, */ | ||
1134 | /* but has no PLD r/w register to test */ | ||
1135 | if (HPI_ADAPTER_FAMILY_ASI(pao->pci. | ||
1136 | subsys_device_id) == | ||
1137 | HPI_ADAPTER_FAMILY_ASI(0x5100)) | ||
1138 | mask = 0x00000000L; | ||
1139 | break; | ||
1140 | case HPI_ADAPTER_FAMILY_ASI(0x8800): | ||
1141 | /* ASI8800 has 16bit path to FPGA */ | ||
1142 | mask = 0xFFFF0000L; | ||
1143 | break; | ||
1144 | } | ||
1145 | test_data = 0xAAAAAA00L & mask; | ||
1146 | /* write to 24 bit Debug register (D31-D8) */ | ||
1147 | hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data); | ||
1148 | read = hpi_read_word(pdo, | ||
1149 | PLD_BASE_ADDRESS + 4L) & mask; | ||
1150 | if (read != test_data) { | ||
1151 | HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data, | ||
1152 | read); | ||
1153 | return HPI6000_ERROR_INIT_PLDTEST1; | ||
1154 | } | ||
1155 | test_data = 0x55555500L & mask; | ||
1156 | hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data); | ||
1157 | read = hpi_read_word(pdo, | ||
1158 | PLD_BASE_ADDRESS + 4L) & mask; | ||
1159 | if (read != test_data) { | ||
1160 | HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data, | ||
1161 | read); | ||
1162 | return HPI6000_ERROR_INIT_PLDTEST2; | ||
1163 | } | ||
1164 | } | ||
1165 | } /* for numDSP */ | ||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | #define PCI_TIMEOUT 100 | ||
1170 | |||
1171 | static int hpi_set_address(struct dsp_obj *pdo, u32 address) | ||
1172 | { | ||
1173 | u32 timeout = PCI_TIMEOUT; | ||
1174 | |||
1175 | do { | ||
1176 | iowrite32(address, pdo->prHPI_address); | ||
1177 | } while (hpi6000_check_PCI2040_error_flag(pdo->pa_parent_adapter, | ||
1178 | H6WRITE) | ||
1179 | && --timeout); | ||
1180 | |||
1181 | if (timeout) | ||
1182 | return 0; | ||
1183 | |||
1184 | return 1; | ||
1185 | } | ||
1186 | |||
1187 | /* write one word to the HPI port */ | ||
1188 | static void hpi_write_word(struct dsp_obj *pdo, u32 address, u32 data) | ||
1189 | { | ||
1190 | if (hpi_set_address(pdo, address)) | ||
1191 | return; | ||
1192 | iowrite32(data, pdo->prHPI_data); | ||
1193 | } | ||
1194 | |||
1195 | /* read one word from the HPI port */ | ||
1196 | static u32 hpi_read_word(struct dsp_obj *pdo, u32 address) | ||
1197 | { | ||
1198 | u32 data = 0; | ||
1199 | |||
1200 | if (hpi_set_address(pdo, address)) | ||
1201 | return 0; /*? no way to return error */ | ||
1202 | |||
1203 | /* take care of errata in revB DSP (2.0.1) */ | ||
1204 | data = ioread32(pdo->prHPI_data); | ||
1205 | return data; | ||
1206 | } | ||
1207 | |||
1208 | /* write a block of 32bit words to the DSP HPI port using auto-inc mode */ | ||
1209 | static void hpi_write_block(struct dsp_obj *pdo, u32 address, u32 *pdata, | ||
1210 | u32 length) | ||
1211 | { | ||
1212 | u16 length16 = length - 1; | ||
1213 | |||
1214 | if (length == 0) | ||
1215 | return; | ||
1216 | |||
1217 | if (hpi_set_address(pdo, address)) | ||
1218 | return; | ||
1219 | |||
1220 | iowrite32_rep(pdo->prHPI_data_auto_inc, pdata, length16); | ||
1221 | |||
1222 | /* take care of errata in revB DSP (2.0.1) */ | ||
1223 | /* must end with non auto-inc */ | ||
1224 | iowrite32(*(pdata + length - 1), pdo->prHPI_data); | ||
1225 | } | ||
1226 | |||
1227 | /** read a block of 32bit words from the DSP HPI port using auto-inc mode | ||
1228 | */ | ||
1229 | static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata, | ||
1230 | u32 length) | ||
1231 | { | ||
1232 | u16 length16 = length - 1; | ||
1233 | |||
1234 | if (length == 0) | ||
1235 | return; | ||
1236 | |||
1237 | if (hpi_set_address(pdo, address)) | ||
1238 | return; | ||
1239 | |||
1240 | ioread32_rep(pdo->prHPI_data_auto_inc, pdata, length16); | ||
1241 | |||
1242 | /* take care of errata in revB DSP (2.0.1) */ | ||
1243 | /* must end with non auto-inc */ | ||
1244 | *(pdata + length - 1) = ioread32(pdo->prHPI_data); | ||
1245 | } | ||
1246 | |||
1247 | static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao, | ||
1248 | u16 dsp_index, u32 hpi_address, u32 *source, u32 count) | ||
1249 | { | ||
1250 | struct dsp_obj *pdo = | ||
1251 | &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index]; | ||
1252 | u32 time_out = PCI_TIMEOUT; | ||
1253 | int c6711_burst_size = 128; | ||
1254 | u32 local_hpi_address = hpi_address; | ||
1255 | int local_count = count; | ||
1256 | int xfer_size; | ||
1257 | u32 *pdata = source; | ||
1258 | |||
1259 | while (local_count) { | ||
1260 | if (local_count > c6711_burst_size) | ||
1261 | xfer_size = c6711_burst_size; | ||
1262 | else | ||
1263 | xfer_size = local_count; | ||
1264 | |||
1265 | time_out = PCI_TIMEOUT; | ||
1266 | do { | ||
1267 | hpi_write_block(pdo, local_hpi_address, pdata, | ||
1268 | xfer_size); | ||
1269 | } while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE) | ||
1270 | && --time_out); | ||
1271 | |||
1272 | if (!time_out) | ||
1273 | break; | ||
1274 | pdata += xfer_size; | ||
1275 | local_hpi_address += sizeof(u32) * xfer_size; | ||
1276 | local_count -= xfer_size; | ||
1277 | } | ||
1278 | |||
1279 | if (time_out) | ||
1280 | return 0; | ||
1281 | else | ||
1282 | return 1; | ||
1283 | } | ||
1284 | |||
1285 | static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao, | ||
1286 | u16 dsp_index, u32 hpi_address, u32 *dest, u32 count) | ||
1287 | { | ||
1288 | struct dsp_obj *pdo = | ||
1289 | &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index]; | ||
1290 | u32 time_out = PCI_TIMEOUT; | ||
1291 | int c6711_burst_size = 16; | ||
1292 | u32 local_hpi_address = hpi_address; | ||
1293 | int local_count = count; | ||
1294 | int xfer_size; | ||
1295 | u32 *pdata = dest; | ||
1296 | u32 loop_count = 0; | ||
1297 | |||
1298 | while (local_count) { | ||
1299 | if (local_count > c6711_burst_size) | ||
1300 | xfer_size = c6711_burst_size; | ||
1301 | else | ||
1302 | xfer_size = local_count; | ||
1303 | |||
1304 | time_out = PCI_TIMEOUT; | ||
1305 | do { | ||
1306 | hpi_read_block(pdo, local_hpi_address, pdata, | ||
1307 | xfer_size); | ||
1308 | } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) | ||
1309 | && --time_out); | ||
1310 | if (!time_out) | ||
1311 | break; | ||
1312 | |||
1313 | pdata += xfer_size; | ||
1314 | local_hpi_address += sizeof(u32) * xfer_size; | ||
1315 | local_count -= xfer_size; | ||
1316 | loop_count++; | ||
1317 | } | ||
1318 | |||
1319 | if (time_out) | ||
1320 | return 0; | ||
1321 | else | ||
1322 | return 1; | ||
1323 | } | ||
1324 | |||
1325 | static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao, | ||
1326 | u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr) | ||
1327 | { | ||
1328 | struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; | ||
1329 | struct dsp_obj *pdo = &phw->ado[dsp_index]; | ||
1330 | u32 timeout; | ||
1331 | u16 ack; | ||
1332 | u32 address; | ||
1333 | u32 length; | ||
1334 | u32 *p_data; | ||
1335 | u16 error = 0; | ||
1336 | |||
1337 | /* does the DSP we are referencing exist? */ | ||
1338 | if (dsp_index >= phw->num_dsp) | ||
1339 | return HPI6000_ERROR_MSG_INVALID_DSP_INDEX; | ||
1340 | |||
1341 | ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE); | ||
1342 | if (ack & HPI_HIF_ERROR_MASK) { | ||
1343 | pao->dsp_crashed++; | ||
1344 | return HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT; | ||
1345 | } | ||
1346 | pao->dsp_crashed = 0; | ||
1347 | |||
1348 | /* send the message */ | ||
1349 | |||
1350 | /* get the address and size */ | ||
1351 | if (phw->message_buffer_address_on_dsp == 0) { | ||
1352 | timeout = TIMEOUT; | ||
1353 | do { | ||
1354 | address = | ||
1355 | hpi_read_word(pdo, | ||
1356 | HPI_HIF_ADDR(message_buffer_address)); | ||
1357 | phw->message_buffer_address_on_dsp = address; | ||
1358 | } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) | ||
1359 | && --timeout); | ||
1360 | if (!timeout) | ||
1361 | return HPI6000_ERROR_MSG_GET_ADR; | ||
1362 | } else | ||
1363 | address = phw->message_buffer_address_on_dsp; | ||
1364 | |||
1365 | /* dwLength = sizeof(struct hpi_message); */ | ||
1366 | length = phm->size; | ||
1367 | |||
1368 | /* send it */ | ||
1369 | p_data = (u32 *)phm; | ||
1370 | if (hpi6000_dsp_block_write32(pao, dsp_index, address, p_data, | ||
1371 | (u16)length / 4)) | ||
1372 | return HPI6000_ERROR_MSG_RESP_BLOCKWRITE32; | ||
1373 | |||
1374 | if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_GET_RESP)) | ||
1375 | return HPI6000_ERROR_MSG_RESP_GETRESPCMD; | ||
1376 | hpi6000_send_dsp_interrupt(pdo); | ||
1377 | |||
1378 | ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_GET_RESP); | ||
1379 | if (ack & HPI_HIF_ERROR_MASK) | ||
1380 | return HPI6000_ERROR_MSG_RESP_GET_RESP_ACK; | ||
1381 | |||
1382 | /* get the address and size */ | ||
1383 | if (phw->response_buffer_address_on_dsp == 0) { | ||
1384 | timeout = TIMEOUT; | ||
1385 | do { | ||
1386 | address = | ||
1387 | hpi_read_word(pdo, | ||
1388 | HPI_HIF_ADDR(response_buffer_address)); | ||
1389 | } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) | ||
1390 | && --timeout); | ||
1391 | phw->response_buffer_address_on_dsp = address; | ||
1392 | |||
1393 | if (!timeout) | ||
1394 | return HPI6000_ERROR_RESP_GET_ADR; | ||
1395 | } else | ||
1396 | address = phw->response_buffer_address_on_dsp; | ||
1397 | |||
1398 | /* read the length of the response back from the DSP */ | ||
1399 | timeout = TIMEOUT; | ||
1400 | do { | ||
1401 | length = hpi_read_word(pdo, HPI_HIF_ADDR(length)); | ||
1402 | } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout); | ||
1403 | if (!timeout) | ||
1404 | length = sizeof(struct hpi_response); | ||
1405 | |||
1406 | /* get it */ | ||
1407 | p_data = (u32 *)phr; | ||
1408 | if (hpi6000_dsp_block_read32(pao, dsp_index, address, p_data, | ||
1409 | (u16)length / 4)) | ||
1410 | return HPI6000_ERROR_MSG_RESP_BLOCKREAD32; | ||
1411 | |||
1412 | /* set i/f back to idle */ | ||
1413 | if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE)) | ||
1414 | return HPI6000_ERROR_MSG_RESP_IDLECMD; | ||
1415 | hpi6000_send_dsp_interrupt(pdo); | ||
1416 | |||
1417 | error = hpi_validate_response(phm, phr); | ||
1418 | return error; | ||
1419 | } | ||
1420 | |||
1421 | /* have to set up the below defines to match stuff in the MAP file */ | ||
1422 | |||
1423 | #define MSG_ADDRESS (HPI_HIF_BASE+0x18) | ||
1424 | #define MSG_LENGTH 11 | ||
1425 | #define RESP_ADDRESS (HPI_HIF_BASE+0x44) | ||
1426 | #define RESP_LENGTH 16 | ||
1427 | #define QUEUE_START (HPI_HIF_BASE+0x88) | ||
1428 | #define QUEUE_SIZE 0x8000 | ||
1429 | |||
1430 | static short hpi6000_send_data_check_adr(u32 address, u32 length_in_dwords) | ||
1431 | { | ||
1432 | /*#define CHECKING // comment this line in to enable checking */ | ||
1433 | #ifdef CHECKING | ||
1434 | if (address < (u32)MSG_ADDRESS) | ||
1435 | return 0; | ||
1436 | if (address > (u32)(QUEUE_START + QUEUE_SIZE)) | ||
1437 | return 0; | ||
1438 | if ((address + (length_in_dwords << 2)) > | ||
1439 | (u32)(QUEUE_START + QUEUE_SIZE)) | ||
1440 | return 0; | ||
1441 | #else | ||
1442 | (void)address; | ||
1443 | (void)length_in_dwords; | ||
1444 | return 1; | ||
1445 | #endif | ||
1446 | } | ||
1447 | |||
1448 | static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index, | ||
1449 | struct hpi_message *phm, struct hpi_response *phr) | ||
1450 | { | ||
1451 | struct dsp_obj *pdo = | ||
1452 | &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index]; | ||
1453 | u32 data_sent = 0; | ||
1454 | u16 ack; | ||
1455 | u32 length, address; | ||
1456 | u32 *p_data = (u32 *)phm->u.d.u.data.pb_data; | ||
1457 | u16 time_out = 8; | ||
1458 | |||
1459 | (void)phr; | ||
1460 | |||
1461 | /* round dwDataSize down to nearest 4 bytes */ | ||
1462 | while ((data_sent < (phm->u.d.u.data.data_size & ~3L)) | ||
1463 | && --time_out) { | ||
1464 | ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE); | ||
1465 | if (ack & HPI_HIF_ERROR_MASK) | ||
1466 | return HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT; | ||
1467 | |||
1468 | if (hpi6000_send_host_command(pao, dsp_index, | ||
1469 | HPI_HIF_SEND_DATA)) | ||
1470 | return HPI6000_ERROR_SEND_DATA_CMD; | ||
1471 | |||
1472 | hpi6000_send_dsp_interrupt(pdo); | ||
1473 | |||
1474 | ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_SEND_DATA); | ||
1475 | |||
1476 | if (ack & HPI_HIF_ERROR_MASK) | ||
1477 | return HPI6000_ERROR_SEND_DATA_ACK; | ||
1478 | |||
1479 | do { | ||
1480 | /* get the address and size */ | ||
1481 | address = hpi_read_word(pdo, HPI_HIF_ADDR(address)); | ||
1482 | /* DSP returns number of DWORDS */ | ||
1483 | length = hpi_read_word(pdo, HPI_HIF_ADDR(length)); | ||
1484 | } while (hpi6000_check_PCI2040_error_flag(pao, H6READ)); | ||
1485 | |||
1486 | if (!hpi6000_send_data_check_adr(address, length)) | ||
1487 | return HPI6000_ERROR_SEND_DATA_ADR; | ||
1488 | |||
1489 | /* send the data. break data into 512 DWORD blocks (2K bytes) | ||
1490 | * and send using block write. 2Kbytes is the max as this is the | ||
1491 | * memory window given to the HPI data register by the PCI2040 | ||
1492 | */ | ||
1493 | |||
1494 | { | ||
1495 | u32 len = length; | ||
1496 | u32 blk_len = 512; | ||
1497 | while (len) { | ||
1498 | if (len < blk_len) | ||
1499 | blk_len = len; | ||
1500 | if (hpi6000_dsp_block_write32(pao, dsp_index, | ||
1501 | address, p_data, blk_len)) | ||
1502 | return HPI6000_ERROR_SEND_DATA_WRITE; | ||
1503 | address += blk_len * 4; | ||
1504 | p_data += blk_len; | ||
1505 | len -= blk_len; | ||
1506 | } | ||
1507 | } | ||
1508 | |||
1509 | if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE)) | ||
1510 | return HPI6000_ERROR_SEND_DATA_IDLECMD; | ||
1511 | |||
1512 | hpi6000_send_dsp_interrupt(pdo); | ||
1513 | |||
1514 | data_sent += length * 4; | ||
1515 | } | ||
1516 | if (!time_out) | ||
1517 | return HPI6000_ERROR_SEND_DATA_TIMEOUT; | ||
1518 | return 0; | ||
1519 | } | ||
1520 | |||
1521 | static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index, | ||
1522 | struct hpi_message *phm, struct hpi_response *phr) | ||
1523 | { | ||
1524 | struct dsp_obj *pdo = | ||
1525 | &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index]; | ||
1526 | u32 data_got = 0; | ||
1527 | u16 ack; | ||
1528 | u32 length, address; | ||
1529 | u32 *p_data = (u32 *)phm->u.d.u.data.pb_data; | ||
1530 | |||
1531 | (void)phr; /* this parameter not used! */ | ||
1532 | |||
1533 | /* round dwDataSize down to nearest 4 bytes */ | ||
1534 | while (data_got < (phm->u.d.u.data.data_size & ~3L)) { | ||
1535 | ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE); | ||
1536 | if (ack & HPI_HIF_ERROR_MASK) | ||
1537 | return HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT; | ||
1538 | |||
1539 | if (hpi6000_send_host_command(pao, dsp_index, | ||
1540 | HPI_HIF_GET_DATA)) | ||
1541 | return HPI6000_ERROR_GET_DATA_CMD; | ||
1542 | hpi6000_send_dsp_interrupt(pdo); | ||
1543 | |||
1544 | ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_GET_DATA); | ||
1545 | |||
1546 | if (ack & HPI_HIF_ERROR_MASK) | ||
1547 | return HPI6000_ERROR_GET_DATA_ACK; | ||
1548 | |||
1549 | /* get the address and size */ | ||
1550 | do { | ||
1551 | address = hpi_read_word(pdo, HPI_HIF_ADDR(address)); | ||
1552 | length = hpi_read_word(pdo, HPI_HIF_ADDR(length)); | ||
1553 | } while (hpi6000_check_PCI2040_error_flag(pao, H6READ)); | ||
1554 | |||
1555 | /* read the data */ | ||
1556 | { | ||
1557 | u32 len = length; | ||
1558 | u32 blk_len = 512; | ||
1559 | while (len) { | ||
1560 | if (len < blk_len) | ||
1561 | blk_len = len; | ||
1562 | if (hpi6000_dsp_block_read32(pao, dsp_index, | ||
1563 | address, p_data, blk_len)) | ||
1564 | return HPI6000_ERROR_GET_DATA_READ; | ||
1565 | address += blk_len * 4; | ||
1566 | p_data += blk_len; | ||
1567 | len -= blk_len; | ||
1568 | } | ||
1569 | } | ||
1570 | |||
1571 | if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE)) | ||
1572 | return HPI6000_ERROR_GET_DATA_IDLECMD; | ||
1573 | hpi6000_send_dsp_interrupt(pdo); | ||
1574 | |||
1575 | data_got += length * 4; | ||
1576 | } | ||
1577 | return 0; | ||
1578 | } | ||
1579 | |||
1580 | static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo) | ||
1581 | { | ||
1582 | iowrite32(0x00030003, pdo->prHPI_control); /* DSPINT */ | ||
1583 | } | ||
1584 | |||
1585 | static short hpi6000_send_host_command(struct hpi_adapter_obj *pao, | ||
1586 | u16 dsp_index, u32 host_cmd) | ||
1587 | { | ||
1588 | struct dsp_obj *pdo = | ||
1589 | &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index]; | ||
1590 | u32 timeout = TIMEOUT; | ||
1591 | |||
1592 | /* set command */ | ||
1593 | do { | ||
1594 | hpi_write_word(pdo, HPI_HIF_ADDR(host_cmd), host_cmd); | ||
1595 | /* flush the FIFO */ | ||
1596 | hpi_set_address(pdo, HPI_HIF_ADDR(host_cmd)); | ||
1597 | } while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE) && --timeout); | ||
1598 | |||
1599 | /* reset the interrupt bit */ | ||
1600 | iowrite32(0x00040004, pdo->prHPI_control); | ||
1601 | |||
1602 | if (timeout) | ||
1603 | return 0; | ||
1604 | else | ||
1605 | return 1; | ||
1606 | } | ||
1607 | |||
1608 | /* if the PCI2040 has recorded an HPI timeout, reset the error and return 1 */ | ||
1609 | static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao, | ||
1610 | u16 read_or_write) | ||
1611 | { | ||
1612 | u32 hPI_error; | ||
1613 | |||
1614 | struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; | ||
1615 | |||
1616 | /* read the error bits from the PCI2040 */ | ||
1617 | hPI_error = ioread32(phw->dw2040_HPICSR + HPI_ERROR_REPORT); | ||
1618 | if (hPI_error) { | ||
1619 | /* reset the error flag */ | ||
1620 | iowrite32(0L, phw->dw2040_HPICSR + HPI_ERROR_REPORT); | ||
1621 | phw->pCI2040HPI_error_count++; | ||
1622 | if (read_or_write == 1) | ||
1623 | gw_pci_read_asserts++; /************* inc global */ | ||
1624 | else | ||
1625 | gw_pci_write_asserts++; | ||
1626 | return 1; | ||
1627 | } else | ||
1628 | return 0; | ||
1629 | } | ||
1630 | |||
1631 | static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index, | ||
1632 | u32 ack_value) | ||
1633 | { | ||
1634 | struct dsp_obj *pdo = | ||
1635 | &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index]; | ||
1636 | u32 ack = 0L; | ||
1637 | u32 timeout; | ||
1638 | u32 hPIC = 0L; | ||
1639 | |||
1640 | /* wait for host interrupt to signal ack is ready */ | ||
1641 | timeout = TIMEOUT; | ||
1642 | while (--timeout) { | ||
1643 | hPIC = ioread32(pdo->prHPI_control); | ||
1644 | if (hPIC & 0x04) /* 0x04 = HINT from DSP */ | ||
1645 | break; | ||
1646 | } | ||
1647 | if (timeout == 0) | ||
1648 | return HPI_HIF_ERROR_MASK; | ||
1649 | |||
1650 | /* wait for dwAckValue */ | ||
1651 | timeout = TIMEOUT; | ||
1652 | while (--timeout) { | ||
1653 | /* read the ack mailbox */ | ||
1654 | ack = hpi_read_word(pdo, HPI_HIF_ADDR(dsp_ack)); | ||
1655 | if (ack == ack_value) | ||
1656 | break; | ||
1657 | if ((ack & HPI_HIF_ERROR_MASK) | ||
1658 | && !hpi6000_check_PCI2040_error_flag(pao, H6READ)) | ||
1659 | break; | ||
1660 | /*for (i=0;i<1000;i++) */ | ||
1661 | /* dwPause=i+1; */ | ||
1662 | } | ||
1663 | if (ack & HPI_HIF_ERROR_MASK) | ||
1664 | /* indicates bad read from DSP - | ||
1665 | typically 0xffffff is read for some reason */ | ||
1666 | ack = HPI_HIF_ERROR_MASK; | ||
1667 | |||
1668 | if (timeout == 0) | ||
1669 | ack = HPI_HIF_ERROR_MASK; | ||
1670 | return (short)ack; | ||
1671 | } | ||
1672 | |||
1673 | static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao, | ||
1674 | struct hpi_message *phm) | ||
1675 | { | ||
1676 | const u16 dsp_index = 0; | ||
1677 | struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; | ||
1678 | struct dsp_obj *pdo = &phw->ado[dsp_index]; | ||
1679 | u32 timeout; | ||
1680 | u32 cache_dirty_flag; | ||
1681 | u16 err; | ||
1682 | |||
1683 | hpios_dsplock_lock(pao); | ||
1684 | |||
1685 | timeout = TIMEOUT; | ||
1686 | do { | ||
1687 | cache_dirty_flag = | ||
1688 | hpi_read_word((struct dsp_obj *)pdo, | ||
1689 | HPI_HIF_ADDR(control_cache_is_dirty)); | ||
1690 | } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout); | ||
1691 | if (!timeout) { | ||
1692 | err = HPI6000_ERROR_CONTROL_CACHE_PARAMS; | ||
1693 | goto unlock; | ||
1694 | } | ||
1695 | |||
1696 | if (cache_dirty_flag) { | ||
1697 | /* read the cached controls */ | ||
1698 | u32 address; | ||
1699 | u32 length; | ||
1700 | |||
1701 | timeout = TIMEOUT; | ||
1702 | if (pdo->control_cache_address_on_dsp == 0) { | ||
1703 | do { | ||
1704 | address = | ||
1705 | hpi_read_word((struct dsp_obj *)pdo, | ||
1706 | HPI_HIF_ADDR(control_cache_address)); | ||
1707 | |||
1708 | length = hpi_read_word((struct dsp_obj *)pdo, | ||
1709 | HPI_HIF_ADDR | ||
1710 | (control_cache_size_in_bytes)); | ||
1711 | } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) | ||
1712 | && --timeout); | ||
1713 | if (!timeout) { | ||
1714 | err = HPI6000_ERROR_CONTROL_CACHE_ADDRLEN; | ||
1715 | goto unlock; | ||
1716 | } | ||
1717 | pdo->control_cache_address_on_dsp = address; | ||
1718 | pdo->control_cache_length_on_dsp = length; | ||
1719 | } else { | ||
1720 | address = pdo->control_cache_address_on_dsp; | ||
1721 | length = pdo->control_cache_length_on_dsp; | ||
1722 | } | ||
1723 | |||
1724 | if (hpi6000_dsp_block_read32(pao, dsp_index, address, | ||
1725 | (u32 *)&phw->control_cache[0], | ||
1726 | length / sizeof(u32))) { | ||
1727 | err = HPI6000_ERROR_CONTROL_CACHE_READ; | ||
1728 | goto unlock; | ||
1729 | } | ||
1730 | do { | ||
1731 | hpi_write_word((struct dsp_obj *)pdo, | ||
1732 | HPI_HIF_ADDR(control_cache_is_dirty), 0); | ||
1733 | /* flush the FIFO */ | ||
1734 | hpi_set_address(pdo, HPI_HIF_ADDR(host_cmd)); | ||
1735 | } while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE) | ||
1736 | && --timeout); | ||
1737 | if (!timeout) { | ||
1738 | err = HPI6000_ERROR_CONTROL_CACHE_FLUSH; | ||
1739 | goto unlock; | ||
1740 | } | ||
1741 | |||
1742 | } | ||
1743 | err = 0; | ||
1744 | |||
1745 | unlock: | ||
1746 | hpios_dsplock_unlock(pao); | ||
1747 | return err; | ||
1748 | } | ||
1749 | |||
1750 | /** Get dsp index for multi DSP adapters only */ | ||
1751 | static u16 get_dsp_index(struct hpi_adapter_obj *pao, struct hpi_message *phm) | ||
1752 | { | ||
1753 | u16 ret = 0; | ||
1754 | switch (phm->object) { | ||
1755 | case HPI_OBJ_ISTREAM: | ||
1756 | if (phm->obj_index < 2) | ||
1757 | ret = 1; | ||
1758 | break; | ||
1759 | case HPI_OBJ_PROFILE: | ||
1760 | ret = phm->obj_index; | ||
1761 | break; | ||
1762 | default: | ||
1763 | break; | ||
1764 | } | ||
1765 | return ret; | ||
1766 | } | ||
1767 | |||
1768 | /** Complete transaction with DSP | ||
1769 | |||
1770 | Send message, get response, send or get stream data if any. | ||
1771 | */ | ||
1772 | static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, | ||
1773 | struct hpi_response *phr) | ||
1774 | { | ||
1775 | u16 error = 0; | ||
1776 | u16 dsp_index = 0; | ||
1777 | u16 num_dsp = ((struct hpi_hw_obj *)pao->priv)->num_dsp; | ||
1778 | hpios_dsplock_lock(pao); | ||
1779 | |||
1780 | if (num_dsp < 2) | ||
1781 | dsp_index = 0; | ||
1782 | else { | ||
1783 | dsp_index = get_dsp_index(pao, phm); | ||
1784 | |||
1785 | /* is this checked on the DSP anyway? */ | ||
1786 | if ((phm->function == HPI_ISTREAM_GROUP_ADD) | ||
1787 | || (phm->function == HPI_OSTREAM_GROUP_ADD)) { | ||
1788 | struct hpi_message hm; | ||
1789 | u16 add_index; | ||
1790 | hm.obj_index = phm->u.d.u.stream.stream_index; | ||
1791 | hm.object = phm->u.d.u.stream.object_type; | ||
1792 | add_index = get_dsp_index(pao, &hm); | ||
1793 | if (add_index != dsp_index) { | ||
1794 | phr->error = HPI_ERROR_NO_INTERDSP_GROUPS; | ||
1795 | return; | ||
1796 | } | ||
1797 | } | ||
1798 | } | ||
1799 | error = hpi6000_message_response_sequence(pao, dsp_index, phm, phr); | ||
1800 | |||
1801 | /* maybe an error response */ | ||
1802 | if (error) { | ||
1803 | /* something failed in the HPI/DSP interface */ | ||
1804 | phr->error = error; | ||
1805 | /* just the header of the response is valid */ | ||
1806 | phr->size = sizeof(struct hpi_response_header); | ||
1807 | goto err; | ||
1808 | } | ||
1809 | |||
1810 | if (phr->error != 0) /* something failed in the DSP */ | ||
1811 | goto err; | ||
1812 | |||
1813 | switch (phm->function) { | ||
1814 | case HPI_OSTREAM_WRITE: | ||
1815 | case HPI_ISTREAM_ANC_WRITE: | ||
1816 | error = hpi6000_send_data(pao, dsp_index, phm, phr); | ||
1817 | break; | ||
1818 | case HPI_ISTREAM_READ: | ||
1819 | case HPI_OSTREAM_ANC_READ: | ||
1820 | error = hpi6000_get_data(pao, dsp_index, phm, phr); | ||
1821 | break; | ||
1822 | case HPI_ADAPTER_GET_ASSERT: | ||
1823 | phr->u.a.adapter_index = 0; /* dsp 0 default */ | ||
1824 | if (num_dsp == 2) { | ||
1825 | if (!phr->u.a.adapter_type) { | ||
1826 | /* no assert from dsp 0, check dsp 1 */ | ||
1827 | error = hpi6000_message_response_sequence(pao, | ||
1828 | 1, phm, phr); | ||
1829 | phr->u.a.adapter_index = 1; | ||
1830 | } | ||
1831 | } | ||
1832 | } | ||
1833 | |||
1834 | if (error) | ||
1835 | phr->error = error; | ||
1836 | |||
1837 | err: | ||
1838 | hpios_dsplock_unlock(pao); | ||
1839 | return; | ||
1840 | } | ||
diff --git a/sound/pci/asihpi/hpi6000.h b/sound/pci/asihpi/hpi6000.h new file mode 100644 index 00000000000..4c7d507c0ec --- /dev/null +++ b/sound/pci/asihpi/hpi6000.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /***************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Public declarations for DSP Proramming Interface to TI C6701 | ||
20 | |||
21 | Shared between hpi6000.c and DSP code | ||
22 | |||
23 | (C) Copyright AudioScience Inc. 1998-2003 | ||
24 | ******************************************************************************/ | ||
25 | |||
26 | #ifndef _HPI6000_H_ | ||
27 | #define _HPI6000_H_ | ||
28 | |||
29 | #define HPI_NMIXER_CONTROLS 200 | ||
30 | |||
31 | /* | ||
32 | * Control caching is always supported in the HPI code. | ||
33 | * The DSP should make sure that dwControlCacheSizeInBytes is initialized to 0 | ||
34 | * during boot to make it in-active. | ||
35 | */ | ||
36 | struct hpi_hif_6000 { | ||
37 | u32 host_cmd; | ||
38 | u32 dsp_ack; | ||
39 | u32 address; | ||
40 | u32 length; | ||
41 | u32 message_buffer_address; | ||
42 | u32 response_buffer_address; | ||
43 | u32 dsp_number; | ||
44 | u32 adapter_info; | ||
45 | u32 control_cache_is_dirty; | ||
46 | u32 control_cache_address; | ||
47 | u32 control_cache_size_in_bytes; | ||
48 | u32 control_cache_count; | ||
49 | }; | ||
50 | |||
51 | #define HPI_HIF_PACK_ADAPTER_INFO(adapter, version_major, version_minor) \ | ||
52 | ((adapter << 16) | (version_major << 8) | version_minor) | ||
53 | #define HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER(adapterinfo) \ | ||
54 | ((adapterinfo >> 16) & 0xffff) | ||
55 | #define HPI_HIF_ADAPTER_INFO_EXTRACT_HWVERSION_MAJOR(adapterinfo) \ | ||
56 | ((adapterinfo >> 8) & 0xff) | ||
57 | #define HPI_HIF_ADAPTER_INFO_EXTRACT_HWVERSION_MINOR(adapterinfo) \ | ||
58 | (adapterinfo & 0xff) | ||
59 | |||
60 | /* Command/status exchanged between host and DSP */ | ||
61 | #define HPI_HIF_IDLE 0 | ||
62 | #define HPI_HIF_SEND_MSG 1 | ||
63 | #define HPI_HIF_GET_RESP 2 | ||
64 | #define HPI_HIF_DATA_MASK 0x10 | ||
65 | #define HPI_HIF_SEND_DATA 0x13 | ||
66 | #define HPI_HIF_GET_DATA 0x14 | ||
67 | #define HPI_HIF_SEND_DONE 5 | ||
68 | #define HPI_HIF_RESET 9 | ||
69 | |||
70 | #endif /* _HPI6000_H_ */ | ||
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c new file mode 100644 index 00000000000..5e88c1fc2b9 --- /dev/null +++ b/sound/pci/asihpi/hpi6205.c | |||
@@ -0,0 +1,2331 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Hardware Programming Interface (HPI) for AudioScience | ||
20 | ASI50xx, AS51xx, ASI6xxx, ASI87xx ASI89xx series adapters. | ||
21 | These PCI and PCIe bus adapters are based on a | ||
22 | TMS320C6205 PCI bus mastering DSP, | ||
23 | and (except ASI50xx) TI TMS320C6xxx floating point DSP | ||
24 | |||
25 | Exported function: | ||
26 | void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) | ||
27 | |||
28 | (C) Copyright AudioScience Inc. 1998-2010 | ||
29 | *******************************************************************************/ | ||
30 | #define SOURCEFILE_NAME "hpi6205.c" | ||
31 | |||
32 | #include "hpi_internal.h" | ||
33 | #include "hpimsginit.h" | ||
34 | #include "hpidebug.h" | ||
35 | #include "hpi6205.h" | ||
36 | #include "hpidspcd.h" | ||
37 | #include "hpicmn.h" | ||
38 | |||
39 | /*****************************************************************************/ | ||
40 | /* HPI6205 specific error codes */ | ||
41 | #define HPI6205_ERROR_BASE 1000 | ||
42 | /*#define HPI6205_ERROR_MEM_ALLOC 1001 */ | ||
43 | #define HPI6205_ERROR_6205_NO_IRQ 1002 | ||
44 | #define HPI6205_ERROR_6205_INIT_FAILED 1003 | ||
45 | /*#define HPI6205_ERROR_MISSING_DSPCODE 1004 */ | ||
46 | #define HPI6205_ERROR_UNKNOWN_PCI_DEVICE 1005 | ||
47 | #define HPI6205_ERROR_6205_REG 1006 | ||
48 | #define HPI6205_ERROR_6205_DSPPAGE 1007 | ||
49 | #define HPI6205_ERROR_BAD_DSPINDEX 1008 | ||
50 | #define HPI6205_ERROR_C6713_HPIC 1009 | ||
51 | #define HPI6205_ERROR_C6713_HPIA 1010 | ||
52 | #define HPI6205_ERROR_C6713_PLL 1011 | ||
53 | #define HPI6205_ERROR_DSP_INTMEM 1012 | ||
54 | #define HPI6205_ERROR_DSP_EXTMEM 1013 | ||
55 | #define HPI6205_ERROR_DSP_PLD 1014 | ||
56 | #define HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT 1015 | ||
57 | #define HPI6205_ERROR_MSG_RESP_TIMEOUT 1016 | ||
58 | #define HPI6205_ERROR_6205_EEPROM 1017 | ||
59 | #define HPI6205_ERROR_DSP_EMIF 1018 | ||
60 | |||
61 | #define hpi6205_error(dsp_index, err) (err) | ||
62 | /*****************************************************************************/ | ||
63 | /* for C6205 PCI i/f */ | ||
64 | /* Host Status Register (HSR) bitfields */ | ||
65 | #define C6205_HSR_INTSRC 0x01 | ||
66 | #define C6205_HSR_INTAVAL 0x02 | ||
67 | #define C6205_HSR_INTAM 0x04 | ||
68 | #define C6205_HSR_CFGERR 0x08 | ||
69 | #define C6205_HSR_EEREAD 0x10 | ||
70 | /* Host-to-DSP Control Register (HDCR) bitfields */ | ||
71 | #define C6205_HDCR_WARMRESET 0x01 | ||
72 | #define C6205_HDCR_DSPINT 0x02 | ||
73 | #define C6205_HDCR_PCIBOOT 0x04 | ||
74 | /* DSP Page Register (DSPP) bitfields, */ | ||
75 | /* defines 4 Mbyte page that BAR0 points to */ | ||
76 | #define C6205_DSPP_MAP1 0x400 | ||
77 | |||
78 | /* BAR0 maps to prefetchable 4 Mbyte memory block set by DSPP. | ||
79 | * BAR1 maps to non-prefetchable 8 Mbyte memory block | ||
80 | * of DSP memory mapped registers (starting at 0x01800000). | ||
81 | * 0x01800000 is hardcoded in the PCI i/f, so that only the offset from this | ||
82 | * needs to be added to the BAR1 base address set in the PCI config reg | ||
83 | */ | ||
84 | #define C6205_BAR1_PCI_IO_OFFSET (0x027FFF0L) | ||
85 | #define C6205_BAR1_HSR (C6205_BAR1_PCI_IO_OFFSET) | ||
86 | #define C6205_BAR1_HDCR (C6205_BAR1_PCI_IO_OFFSET+4) | ||
87 | #define C6205_BAR1_DSPP (C6205_BAR1_PCI_IO_OFFSET+8) | ||
88 | |||
89 | /* used to control LED (revA) and reset C6713 (revB) */ | ||
90 | #define C6205_BAR0_TIMER1_CTL (0x01980000L) | ||
91 | |||
92 | /* For first 6713 in CE1 space, using DA17,16,2 */ | ||
93 | #define HPICL_ADDR 0x01400000L | ||
94 | #define HPICH_ADDR 0x01400004L | ||
95 | #define HPIAL_ADDR 0x01410000L | ||
96 | #define HPIAH_ADDR 0x01410004L | ||
97 | #define HPIDIL_ADDR 0x01420000L | ||
98 | #define HPIDIH_ADDR 0x01420004L | ||
99 | #define HPIDL_ADDR 0x01430000L | ||
100 | #define HPIDH_ADDR 0x01430004L | ||
101 | |||
102 | #define C6713_EMIF_GCTL 0x01800000 | ||
103 | #define C6713_EMIF_CE1 0x01800004 | ||
104 | #define C6713_EMIF_CE0 0x01800008 | ||
105 | #define C6713_EMIF_CE2 0x01800010 | ||
106 | #define C6713_EMIF_CE3 0x01800014 | ||
107 | #define C6713_EMIF_SDRAMCTL 0x01800018 | ||
108 | #define C6713_EMIF_SDRAMTIMING 0x0180001C | ||
109 | #define C6713_EMIF_SDRAMEXT 0x01800020 | ||
110 | |||
111 | struct hpi_hw_obj { | ||
112 | /* PCI registers */ | ||
113 | __iomem u32 *prHSR; | ||
114 | __iomem u32 *prHDCR; | ||
115 | __iomem u32 *prDSPP; | ||
116 | |||
117 | u32 dsp_page; | ||
118 | |||
119 | struct consistent_dma_area h_locked_mem; | ||
120 | struct bus_master_interface *p_interface_buffer; | ||
121 | |||
122 | u16 flag_outstream_just_reset[HPI_MAX_STREAMS]; | ||
123 | /* a non-NULL handle means there is an HPI allocated buffer */ | ||
124 | struct consistent_dma_area instream_host_buffers[HPI_MAX_STREAMS]; | ||
125 | struct consistent_dma_area outstream_host_buffers[HPI_MAX_STREAMS]; | ||
126 | /* non-zero size means a buffer exists, may be external */ | ||
127 | u32 instream_host_buffer_size[HPI_MAX_STREAMS]; | ||
128 | u32 outstream_host_buffer_size[HPI_MAX_STREAMS]; | ||
129 | |||
130 | struct consistent_dma_area h_control_cache; | ||
131 | struct consistent_dma_area h_async_event_buffer; | ||
132 | /* struct hpi_control_cache_single *pControlCache; */ | ||
133 | struct hpi_async_event *p_async_event_buffer; | ||
134 | struct hpi_control_cache *p_cache; | ||
135 | }; | ||
136 | |||
137 | /*****************************************************************************/ | ||
138 | /* local prototypes */ | ||
139 | |||
140 | #define check_before_bbm_copy(status, p_bbm_data, l_first_write, l_second_write) | ||
141 | |||
142 | static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us); | ||
143 | |||
144 | static void send_dsp_command(struct hpi_hw_obj *phw, int cmd); | ||
145 | |||
146 | static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, | ||
147 | u32 *pos_error_code); | ||
148 | |||
149 | static u16 message_response_sequence(struct hpi_adapter_obj *pao, | ||
150 | struct hpi_message *phm, struct hpi_response *phr); | ||
151 | |||
152 | static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, | ||
153 | struct hpi_response *phr); | ||
154 | |||
155 | #define HPI6205_TIMEOUT 1000000 | ||
156 | |||
157 | static void subsys_create_adapter(struct hpi_message *phm, | ||
158 | struct hpi_response *phr); | ||
159 | static void subsys_delete_adapter(struct hpi_message *phm, | ||
160 | struct hpi_response *phr); | ||
161 | |||
162 | static u16 create_adapter_obj(struct hpi_adapter_obj *pao, | ||
163 | u32 *pos_error_code); | ||
164 | |||
165 | static void delete_adapter_obj(struct hpi_adapter_obj *pao); | ||
166 | |||
167 | static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao, | ||
168 | struct hpi_message *phm, struct hpi_response *phr); | ||
169 | |||
170 | static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao, | ||
171 | struct hpi_message *phm, struct hpi_response *phr); | ||
172 | |||
173 | static void outstream_host_buffer_free(struct hpi_adapter_obj *pao, | ||
174 | struct hpi_message *phm, struct hpi_response *phr); | ||
175 | static void outstream_write(struct hpi_adapter_obj *pao, | ||
176 | struct hpi_message *phm, struct hpi_response *phr); | ||
177 | |||
178 | static void outstream_get_info(struct hpi_adapter_obj *pao, | ||
179 | struct hpi_message *phm, struct hpi_response *phr); | ||
180 | |||
181 | static void outstream_start(struct hpi_adapter_obj *pao, | ||
182 | struct hpi_message *phm, struct hpi_response *phr); | ||
183 | |||
184 | static void outstream_open(struct hpi_adapter_obj *pao, | ||
185 | struct hpi_message *phm, struct hpi_response *phr); | ||
186 | |||
187 | static void outstream_reset(struct hpi_adapter_obj *pao, | ||
188 | struct hpi_message *phm, struct hpi_response *phr); | ||
189 | |||
190 | static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao, | ||
191 | struct hpi_message *phm, struct hpi_response *phr); | ||
192 | |||
193 | static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao, | ||
194 | struct hpi_message *phm, struct hpi_response *phr); | ||
195 | |||
196 | static void instream_host_buffer_free(struct hpi_adapter_obj *pao, | ||
197 | struct hpi_message *phm, struct hpi_response *phr); | ||
198 | |||
199 | static void instream_read(struct hpi_adapter_obj *pao, | ||
200 | struct hpi_message *phm, struct hpi_response *phr); | ||
201 | |||
202 | static void instream_get_info(struct hpi_adapter_obj *pao, | ||
203 | struct hpi_message *phm, struct hpi_response *phr); | ||
204 | |||
205 | static void instream_start(struct hpi_adapter_obj *pao, | ||
206 | struct hpi_message *phm, struct hpi_response *phr); | ||
207 | |||
208 | static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index, | ||
209 | u32 address); | ||
210 | |||
211 | static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index, | ||
212 | u32 address, u32 data); | ||
213 | |||
214 | static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, | ||
215 | int dsp_index); | ||
216 | |||
217 | static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index, | ||
218 | u32 address, u32 length); | ||
219 | |||
220 | static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao, | ||
221 | int dsp_index); | ||
222 | |||
223 | static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao, | ||
224 | int dsp_index); | ||
225 | |||
226 | static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index); | ||
227 | |||
228 | /*****************************************************************************/ | ||
229 | |||
230 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | ||
231 | { | ||
232 | |||
233 | switch (phm->function) { | ||
234 | case HPI_SUBSYS_OPEN: | ||
235 | case HPI_SUBSYS_CLOSE: | ||
236 | case HPI_SUBSYS_GET_INFO: | ||
237 | case HPI_SUBSYS_DRIVER_UNLOAD: | ||
238 | case HPI_SUBSYS_DRIVER_LOAD: | ||
239 | case HPI_SUBSYS_FIND_ADAPTERS: | ||
240 | /* messages that should not get here */ | ||
241 | phr->error = HPI_ERROR_UNIMPLEMENTED; | ||
242 | break; | ||
243 | case HPI_SUBSYS_CREATE_ADAPTER: | ||
244 | subsys_create_adapter(phm, phr); | ||
245 | break; | ||
246 | case HPI_SUBSYS_DELETE_ADAPTER: | ||
247 | subsys_delete_adapter(phm, phr); | ||
248 | break; | ||
249 | default: | ||
250 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | static void control_message(struct hpi_adapter_obj *pao, | ||
256 | struct hpi_message *phm, struct hpi_response *phr) | ||
257 | { | ||
258 | |||
259 | struct hpi_hw_obj *phw = pao->priv; | ||
260 | |||
261 | switch (phm->function) { | ||
262 | case HPI_CONTROL_GET_STATE: | ||
263 | if (pao->has_control_cache) { | ||
264 | rmb(); /* make sure we see updates DM_aed from DSP */ | ||
265 | if (hpi_check_control_cache(phw->p_cache, phm, phr)) | ||
266 | break; | ||
267 | } | ||
268 | hw_message(pao, phm, phr); | ||
269 | break; | ||
270 | case HPI_CONTROL_GET_INFO: | ||
271 | hw_message(pao, phm, phr); | ||
272 | break; | ||
273 | case HPI_CONTROL_SET_STATE: | ||
274 | hw_message(pao, phm, phr); | ||
275 | if (pao->has_control_cache) | ||
276 | hpi_sync_control_cache(phw->p_cache, phm, phr); | ||
277 | break; | ||
278 | default: | ||
279 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
280 | break; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static void adapter_message(struct hpi_adapter_obj *pao, | ||
285 | struct hpi_message *phm, struct hpi_response *phr) | ||
286 | { | ||
287 | switch (phm->function) { | ||
288 | default: | ||
289 | hw_message(pao, phm, phr); | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | static void outstream_message(struct hpi_adapter_obj *pao, | ||
295 | struct hpi_message *phm, struct hpi_response *phr) | ||
296 | { | ||
297 | |||
298 | if (phm->obj_index >= HPI_MAX_STREAMS) { | ||
299 | phr->error = HPI_ERROR_INVALID_STREAM; | ||
300 | HPI_DEBUG_LOG(WARNING, | ||
301 | "message referencing invalid stream %d " | ||
302 | "on adapter index %d\n", phm->obj_index, | ||
303 | phm->adapter_index); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | switch (phm->function) { | ||
308 | case HPI_OSTREAM_WRITE: | ||
309 | outstream_write(pao, phm, phr); | ||
310 | break; | ||
311 | case HPI_OSTREAM_GET_INFO: | ||
312 | outstream_get_info(pao, phm, phr); | ||
313 | break; | ||
314 | case HPI_OSTREAM_HOSTBUFFER_ALLOC: | ||
315 | outstream_host_buffer_allocate(pao, phm, phr); | ||
316 | break; | ||
317 | case HPI_OSTREAM_HOSTBUFFER_GET_INFO: | ||
318 | outstream_host_buffer_get_info(pao, phm, phr); | ||
319 | break; | ||
320 | case HPI_OSTREAM_HOSTBUFFER_FREE: | ||
321 | outstream_host_buffer_free(pao, phm, phr); | ||
322 | break; | ||
323 | case HPI_OSTREAM_START: | ||
324 | outstream_start(pao, phm, phr); | ||
325 | break; | ||
326 | case HPI_OSTREAM_OPEN: | ||
327 | outstream_open(pao, phm, phr); | ||
328 | break; | ||
329 | case HPI_OSTREAM_RESET: | ||
330 | outstream_reset(pao, phm, phr); | ||
331 | break; | ||
332 | default: | ||
333 | hw_message(pao, phm, phr); | ||
334 | break; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | static void instream_message(struct hpi_adapter_obj *pao, | ||
339 | struct hpi_message *phm, struct hpi_response *phr) | ||
340 | { | ||
341 | |||
342 | if (phm->obj_index >= HPI_MAX_STREAMS) { | ||
343 | phr->error = HPI_ERROR_INVALID_STREAM; | ||
344 | HPI_DEBUG_LOG(WARNING, | ||
345 | "message referencing invalid stream %d " | ||
346 | "on adapter index %d\n", phm->obj_index, | ||
347 | phm->adapter_index); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | switch (phm->function) { | ||
352 | case HPI_ISTREAM_READ: | ||
353 | instream_read(pao, phm, phr); | ||
354 | break; | ||
355 | case HPI_ISTREAM_GET_INFO: | ||
356 | instream_get_info(pao, phm, phr); | ||
357 | break; | ||
358 | case HPI_ISTREAM_HOSTBUFFER_ALLOC: | ||
359 | instream_host_buffer_allocate(pao, phm, phr); | ||
360 | break; | ||
361 | case HPI_ISTREAM_HOSTBUFFER_GET_INFO: | ||
362 | instream_host_buffer_get_info(pao, phm, phr); | ||
363 | break; | ||
364 | case HPI_ISTREAM_HOSTBUFFER_FREE: | ||
365 | instream_host_buffer_free(pao, phm, phr); | ||
366 | break; | ||
367 | case HPI_ISTREAM_START: | ||
368 | instream_start(pao, phm, phr); | ||
369 | break; | ||
370 | default: | ||
371 | hw_message(pao, phm, phr); | ||
372 | break; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | /*****************************************************************************/ | ||
377 | /** Entry point to this HPI backend | ||
378 | * All calls to the HPI start here | ||
379 | */ | ||
380 | void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) | ||
381 | { | ||
382 | struct hpi_adapter_obj *pao = NULL; | ||
383 | |||
384 | /* subsytem messages are processed by every HPI. | ||
385 | * All other messages are ignored unless the adapter index matches | ||
386 | * an adapter in the HPI | ||
387 | */ | ||
388 | HPI_DEBUG_LOG(DEBUG, "HPI obj=%d, func=%d\n", phm->object, | ||
389 | phm->function); | ||
390 | |||
391 | /* if Dsp has crashed then do not communicate with it any more */ | ||
392 | if (phm->object != HPI_OBJ_SUBSYSTEM) { | ||
393 | pao = hpi_find_adapter(phm->adapter_index); | ||
394 | if (!pao) { | ||
395 | HPI_DEBUG_LOG(DEBUG, | ||
396 | " %d,%d refused, for another HPI?\n", | ||
397 | phm->object, phm->function); | ||
398 | return; | ||
399 | } | ||
400 | |||
401 | if ((pao->dsp_crashed >= 10) | ||
402 | && (phm->function != HPI_ADAPTER_DEBUG_READ)) { | ||
403 | /* allow last resort debug read even after crash */ | ||
404 | hpi_init_response(phr, phm->object, phm->function, | ||
405 | HPI_ERROR_DSP_HARDWARE); | ||
406 | HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", | ||
407 | phm->object, phm->function); | ||
408 | return; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | /* Init default response */ | ||
413 | if (phm->function != HPI_SUBSYS_CREATE_ADAPTER) | ||
414 | hpi_init_response(phr, phm->object, phm->function, | ||
415 | HPI_ERROR_PROCESSING_MESSAGE); | ||
416 | |||
417 | HPI_DEBUG_LOG(VERBOSE, "start of switch\n"); | ||
418 | switch (phm->type) { | ||
419 | case HPI_TYPE_MESSAGE: | ||
420 | switch (phm->object) { | ||
421 | case HPI_OBJ_SUBSYSTEM: | ||
422 | subsys_message(phm, phr); | ||
423 | break; | ||
424 | |||
425 | case HPI_OBJ_ADAPTER: | ||
426 | phr->size = | ||
427 | sizeof(struct hpi_response_header) + | ||
428 | sizeof(struct hpi_adapter_res); | ||
429 | adapter_message(pao, phm, phr); | ||
430 | break; | ||
431 | |||
432 | case HPI_OBJ_CONTROLEX: | ||
433 | case HPI_OBJ_CONTROL: | ||
434 | control_message(pao, phm, phr); | ||
435 | break; | ||
436 | |||
437 | case HPI_OBJ_OSTREAM: | ||
438 | outstream_message(pao, phm, phr); | ||
439 | break; | ||
440 | |||
441 | case HPI_OBJ_ISTREAM: | ||
442 | instream_message(pao, phm, phr); | ||
443 | break; | ||
444 | |||
445 | default: | ||
446 | hw_message(pao, phm, phr); | ||
447 | break; | ||
448 | } | ||
449 | break; | ||
450 | |||
451 | default: | ||
452 | phr->error = HPI_ERROR_INVALID_TYPE; | ||
453 | break; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | /*****************************************************************************/ | ||
458 | /* SUBSYSTEM */ | ||
459 | |||
460 | /** Create an adapter object and initialise it based on resource information | ||
461 | * passed in in the message | ||
462 | * *** NOTE - you cannot use this function AND the FindAdapters function at the | ||
463 | * same time, the application must use only one of them to get the adapters *** | ||
464 | */ | ||
465 | static void subsys_create_adapter(struct hpi_message *phm, | ||
466 | struct hpi_response *phr) | ||
467 | { | ||
468 | /* create temp adapter obj, because we don't know what index yet */ | ||
469 | struct hpi_adapter_obj ao; | ||
470 | u32 os_error_code; | ||
471 | u16 err; | ||
472 | |||
473 | HPI_DEBUG_LOG(DEBUG, " subsys_create_adapter\n"); | ||
474 | |||
475 | memset(&ao, 0, sizeof(ao)); | ||
476 | |||
477 | /* this HPI only creates adapters for TI/PCI devices */ | ||
478 | if (phm->u.s.resource.bus_type != HPI_BUS_PCI) | ||
479 | return; | ||
480 | if (phm->u.s.resource.r.pci->vendor_id != HPI_PCI_VENDOR_ID_TI) | ||
481 | return; | ||
482 | if (phm->u.s.resource.r.pci->device_id != HPI_PCI_DEV_ID_DSP6205) | ||
483 | return; | ||
484 | |||
485 | ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL); | ||
486 | if (!ao.priv) { | ||
487 | HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n"); | ||
488 | phr->error = HPI_ERROR_MEMORY_ALLOC; | ||
489 | return; | ||
490 | } | ||
491 | |||
492 | ao.pci = *phm->u.s.resource.r.pci; | ||
493 | err = create_adapter_obj(&ao, &os_error_code); | ||
494 | if (!err) | ||
495 | err = hpi_add_adapter(&ao); | ||
496 | if (err) { | ||
497 | phr->u.s.data = os_error_code; | ||
498 | delete_adapter_obj(&ao); | ||
499 | phr->error = err; | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type; | ||
504 | phr->u.s.adapter_index = ao.index; | ||
505 | phr->u.s.num_adapters++; | ||
506 | phr->error = 0; | ||
507 | } | ||
508 | |||
509 | /** delete an adapter - required by WDM driver */ | ||
510 | static void subsys_delete_adapter(struct hpi_message *phm, | ||
511 | struct hpi_response *phr) | ||
512 | { | ||
513 | struct hpi_adapter_obj *pao; | ||
514 | struct hpi_hw_obj *phw; | ||
515 | |||
516 | pao = hpi_find_adapter(phm->adapter_index); | ||
517 | if (!pao) { | ||
518 | phr->error = HPI_ERROR_INVALID_OBJ_INDEX; | ||
519 | return; | ||
520 | } | ||
521 | phw = (struct hpi_hw_obj *)pao->priv; | ||
522 | /* reset adapter h/w */ | ||
523 | /* Reset C6713 #1 */ | ||
524 | boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0); | ||
525 | /* reset C6205 */ | ||
526 | iowrite32(C6205_HDCR_WARMRESET, phw->prHDCR); | ||
527 | |||
528 | delete_adapter_obj(pao); | ||
529 | phr->error = 0; | ||
530 | } | ||
531 | |||
532 | /** Create adapter object | ||
533 | allocate buffers, bootload DSPs, initialise control cache | ||
534 | */ | ||
535 | static u16 create_adapter_obj(struct hpi_adapter_obj *pao, | ||
536 | u32 *pos_error_code) | ||
537 | { | ||
538 | struct hpi_hw_obj *phw = pao->priv; | ||
539 | struct bus_master_interface *interface; | ||
540 | u32 phys_addr; | ||
541 | #ifndef HPI6205_NO_HSR_POLL | ||
542 | u32 time_out = HPI6205_TIMEOUT; | ||
543 | u32 temp1; | ||
544 | #endif | ||
545 | int i; | ||
546 | u16 err; | ||
547 | |||
548 | /* init error reporting */ | ||
549 | pao->dsp_crashed = 0; | ||
550 | |||
551 | for (i = 0; i < HPI_MAX_STREAMS; i++) | ||
552 | phw->flag_outstream_just_reset[i] = 1; | ||
553 | |||
554 | /* The C6205 memory area 1 is 8Mbyte window into DSP registers */ | ||
555 | phw->prHSR = | ||
556 | pao->pci.ap_mem_base[1] + | ||
557 | C6205_BAR1_HSR / sizeof(*pao->pci.ap_mem_base[1]); | ||
558 | phw->prHDCR = | ||
559 | pao->pci.ap_mem_base[1] + | ||
560 | C6205_BAR1_HDCR / sizeof(*pao->pci.ap_mem_base[1]); | ||
561 | phw->prDSPP = | ||
562 | pao->pci.ap_mem_base[1] + | ||
563 | C6205_BAR1_DSPP / sizeof(*pao->pci.ap_mem_base[1]); | ||
564 | |||
565 | pao->has_control_cache = 0; | ||
566 | |||
567 | if (hpios_locked_mem_alloc(&phw->h_locked_mem, | ||
568 | sizeof(struct bus_master_interface), | ||
569 | pao->pci.p_os_data)) | ||
570 | phw->p_interface_buffer = NULL; | ||
571 | else if (hpios_locked_mem_get_virt_addr(&phw->h_locked_mem, | ||
572 | (void *)&phw->p_interface_buffer)) | ||
573 | phw->p_interface_buffer = NULL; | ||
574 | |||
575 | HPI_DEBUG_LOG(DEBUG, "interface buffer address %p\n", | ||
576 | phw->p_interface_buffer); | ||
577 | |||
578 | if (phw->p_interface_buffer) { | ||
579 | memset((void *)phw->p_interface_buffer, 0, | ||
580 | sizeof(struct bus_master_interface)); | ||
581 | phw->p_interface_buffer->dsp_ack = H620_HIF_UNKNOWN; | ||
582 | } | ||
583 | |||
584 | err = adapter_boot_load_dsp(pao, pos_error_code); | ||
585 | if (err) | ||
586 | /* no need to clean up as SubSysCreateAdapter */ | ||
587 | /* calls DeleteAdapter on error. */ | ||
588 | return err; | ||
589 | |||
590 | HPI_DEBUG_LOG(INFO, "load DSP code OK\n"); | ||
591 | |||
592 | /* allow boot load even if mem alloc wont work */ | ||
593 | if (!phw->p_interface_buffer) | ||
594 | return hpi6205_error(0, HPI_ERROR_MEMORY_ALLOC); | ||
595 | |||
596 | interface = phw->p_interface_buffer; | ||
597 | |||
598 | #ifndef HPI6205_NO_HSR_POLL | ||
599 | /* wait for first interrupt indicating the DSP init is done */ | ||
600 | time_out = HPI6205_TIMEOUT * 10; | ||
601 | temp1 = 0; | ||
602 | while (((temp1 & C6205_HSR_INTSRC) == 0) && --time_out) | ||
603 | temp1 = ioread32(phw->prHSR); | ||
604 | |||
605 | if (temp1 & C6205_HSR_INTSRC) | ||
606 | HPI_DEBUG_LOG(INFO, | ||
607 | "interrupt confirming DSP code running OK\n"); | ||
608 | else { | ||
609 | HPI_DEBUG_LOG(ERROR, | ||
610 | "timed out waiting for interrupt " | ||
611 | "confirming DSP code running\n"); | ||
612 | return hpi6205_error(0, HPI6205_ERROR_6205_NO_IRQ); | ||
613 | } | ||
614 | |||
615 | /* reset the interrupt */ | ||
616 | iowrite32(C6205_HSR_INTSRC, phw->prHSR); | ||
617 | #endif | ||
618 | |||
619 | /* make sure the DSP has started ok */ | ||
620 | if (!wait_dsp_ack(phw, H620_HIF_RESET, HPI6205_TIMEOUT * 10)) { | ||
621 | HPI_DEBUG_LOG(ERROR, "timed out waiting reset state \n"); | ||
622 | return hpi6205_error(0, HPI6205_ERROR_6205_INIT_FAILED); | ||
623 | } | ||
624 | /* Note that *pao, *phw are zeroed after allocation, | ||
625 | * so pointers and flags are NULL by default. | ||
626 | * Allocate bus mastering control cache buffer and tell the DSP about it | ||
627 | */ | ||
628 | if (interface->control_cache.number_of_controls) { | ||
629 | void *p_control_cache_virtual; | ||
630 | |||
631 | err = hpios_locked_mem_alloc(&phw->h_control_cache, | ||
632 | interface->control_cache.size_in_bytes, | ||
633 | pao->pci.p_os_data); | ||
634 | if (!err) | ||
635 | err = hpios_locked_mem_get_virt_addr(&phw-> | ||
636 | h_control_cache, &p_control_cache_virtual); | ||
637 | if (!err) { | ||
638 | memset(p_control_cache_virtual, 0, | ||
639 | interface->control_cache.size_in_bytes); | ||
640 | |||
641 | phw->p_cache = | ||
642 | hpi_alloc_control_cache(interface-> | ||
643 | control_cache.number_of_controls, | ||
644 | interface->control_cache.size_in_bytes, | ||
645 | (struct hpi_control_cache_info *) | ||
646 | p_control_cache_virtual); | ||
647 | } | ||
648 | if (!err) { | ||
649 | err = hpios_locked_mem_get_phys_addr(&phw-> | ||
650 | h_control_cache, &phys_addr); | ||
651 | interface->control_cache.physical_address32 = | ||
652 | phys_addr; | ||
653 | } | ||
654 | |||
655 | if (!err) | ||
656 | pao->has_control_cache = 1; | ||
657 | else { | ||
658 | if (hpios_locked_mem_valid(&phw->h_control_cache)) | ||
659 | hpios_locked_mem_free(&phw->h_control_cache); | ||
660 | pao->has_control_cache = 0; | ||
661 | } | ||
662 | } | ||
663 | /* allocate bus mastering async buffer and tell the DSP about it */ | ||
664 | if (interface->async_buffer.b.size) { | ||
665 | err = hpios_locked_mem_alloc(&phw->h_async_event_buffer, | ||
666 | interface->async_buffer.b.size * | ||
667 | sizeof(struct hpi_async_event), pao->pci.p_os_data); | ||
668 | if (!err) | ||
669 | err = hpios_locked_mem_get_virt_addr | ||
670 | (&phw->h_async_event_buffer, (void *) | ||
671 | &phw->p_async_event_buffer); | ||
672 | if (!err) | ||
673 | memset((void *)phw->p_async_event_buffer, 0, | ||
674 | interface->async_buffer.b.size * | ||
675 | sizeof(struct hpi_async_event)); | ||
676 | if (!err) { | ||
677 | err = hpios_locked_mem_get_phys_addr | ||
678 | (&phw->h_async_event_buffer, &phys_addr); | ||
679 | interface->async_buffer.physical_address32 = | ||
680 | phys_addr; | ||
681 | } | ||
682 | if (err) { | ||
683 | if (hpios_locked_mem_valid(&phw-> | ||
684 | h_async_event_buffer)) { | ||
685 | hpios_locked_mem_free | ||
686 | (&phw->h_async_event_buffer); | ||
687 | phw->p_async_event_buffer = NULL; | ||
688 | } | ||
689 | } | ||
690 | } | ||
691 | send_dsp_command(phw, H620_HIF_IDLE); | ||
692 | |||
693 | { | ||
694 | struct hpi_message hM; | ||
695 | struct hpi_response hR; | ||
696 | u32 max_streams; | ||
697 | |||
698 | HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n"); | ||
699 | memset(&hM, 0, sizeof(hM)); | ||
700 | hM.type = HPI_TYPE_MESSAGE; | ||
701 | hM.size = sizeof(hM); | ||
702 | hM.object = HPI_OBJ_ADAPTER; | ||
703 | hM.function = HPI_ADAPTER_GET_INFO; | ||
704 | hM.adapter_index = 0; | ||
705 | memset(&hR, 0, sizeof(hR)); | ||
706 | hR.size = sizeof(hR); | ||
707 | |||
708 | err = message_response_sequence(pao, &hM, &hR); | ||
709 | if (err) { | ||
710 | HPI_DEBUG_LOG(ERROR, "message transport error %d\n", | ||
711 | err); | ||
712 | return err; | ||
713 | } | ||
714 | if (hR.error) | ||
715 | return hR.error; | ||
716 | |||
717 | pao->adapter_type = hR.u.a.adapter_type; | ||
718 | pao->index = hR.u.a.adapter_index; | ||
719 | |||
720 | max_streams = hR.u.a.num_outstreams + hR.u.a.num_instreams; | ||
721 | |||
722 | hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams, | ||
723 | 65536, pao->pci.p_os_data); | ||
724 | |||
725 | HPI_DEBUG_LOG(VERBOSE, | ||
726 | "got adapter info type %x index %d serial %d\n", | ||
727 | hR.u.a.adapter_type, hR.u.a.adapter_index, | ||
728 | hR.u.a.serial_number); | ||
729 | } | ||
730 | |||
731 | pao->open = 0; /* upon creation the adapter is closed */ | ||
732 | |||
733 | HPI_DEBUG_LOG(INFO, "bootload DSP OK\n"); | ||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | /** Free memory areas allocated by adapter | ||
738 | * this routine is called from SubSysDeleteAdapter, | ||
739 | * and SubSysCreateAdapter if duplicate index | ||
740 | */ | ||
741 | static void delete_adapter_obj(struct hpi_adapter_obj *pao) | ||
742 | { | ||
743 | struct hpi_hw_obj *phw; | ||
744 | int i; | ||
745 | |||
746 | phw = pao->priv; | ||
747 | |||
748 | if (hpios_locked_mem_valid(&phw->h_async_event_buffer)) { | ||
749 | hpios_locked_mem_free(&phw->h_async_event_buffer); | ||
750 | phw->p_async_event_buffer = NULL; | ||
751 | } | ||
752 | |||
753 | if (hpios_locked_mem_valid(&phw->h_control_cache)) { | ||
754 | hpios_locked_mem_free(&phw->h_control_cache); | ||
755 | hpi_free_control_cache(phw->p_cache); | ||
756 | } | ||
757 | |||
758 | if (hpios_locked_mem_valid(&phw->h_locked_mem)) { | ||
759 | hpios_locked_mem_free(&phw->h_locked_mem); | ||
760 | phw->p_interface_buffer = NULL; | ||
761 | } | ||
762 | |||
763 | for (i = 0; i < HPI_MAX_STREAMS; i++) | ||
764 | if (hpios_locked_mem_valid(&phw->instream_host_buffers[i])) { | ||
765 | hpios_locked_mem_free(&phw->instream_host_buffers[i]); | ||
766 | /*?phw->InStreamHostBuffers[i] = NULL; */ | ||
767 | phw->instream_host_buffer_size[i] = 0; | ||
768 | } | ||
769 | |||
770 | for (i = 0; i < HPI_MAX_STREAMS; i++) | ||
771 | if (hpios_locked_mem_valid(&phw->outstream_host_buffers[i])) { | ||
772 | hpios_locked_mem_free(&phw->outstream_host_buffers | ||
773 | [i]); | ||
774 | phw->outstream_host_buffer_size[i] = 0; | ||
775 | } | ||
776 | |||
777 | hpios_locked_mem_unprepare(pao->pci.p_os_data); | ||
778 | |||
779 | hpi_delete_adapter(pao); | ||
780 | kfree(phw); | ||
781 | } | ||
782 | |||
783 | /*****************************************************************************/ | ||
784 | /* OutStream Host buffer functions */ | ||
785 | |||
786 | /** Allocate or attach buffer for busmastering | ||
787 | */ | ||
788 | static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao, | ||
789 | struct hpi_message *phm, struct hpi_response *phr) | ||
790 | { | ||
791 | u16 err = 0; | ||
792 | u32 command = phm->u.d.u.buffer.command; | ||
793 | struct hpi_hw_obj *phw = pao->priv; | ||
794 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
795 | |||
796 | hpi_init_response(phr, phm->object, phm->function, 0); | ||
797 | |||
798 | if (command == HPI_BUFFER_CMD_EXTERNAL | ||
799 | || command == HPI_BUFFER_CMD_INTERNAL_ALLOC) { | ||
800 | /* ALLOC phase, allocate a buffer with power of 2 size, | ||
801 | get its bus address for PCI bus mastering | ||
802 | */ | ||
803 | phm->u.d.u.buffer.buffer_size = | ||
804 | roundup_pow_of_two(phm->u.d.u.buffer.buffer_size); | ||
805 | /* return old size and allocated size, | ||
806 | so caller can detect change */ | ||
807 | phr->u.d.u.stream_info.data_available = | ||
808 | phw->outstream_host_buffer_size[phm->obj_index]; | ||
809 | phr->u.d.u.stream_info.buffer_size = | ||
810 | phm->u.d.u.buffer.buffer_size; | ||
811 | |||
812 | if (phw->outstream_host_buffer_size[phm->obj_index] == | ||
813 | phm->u.d.u.buffer.buffer_size) { | ||
814 | /* Same size, no action required */ | ||
815 | return; | ||
816 | } | ||
817 | |||
818 | if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm-> | ||
819 | obj_index])) | ||
820 | hpios_locked_mem_free(&phw->outstream_host_buffers | ||
821 | [phm->obj_index]); | ||
822 | |||
823 | err = hpios_locked_mem_alloc(&phw->outstream_host_buffers | ||
824 | [phm->obj_index], phm->u.d.u.buffer.buffer_size, | ||
825 | pao->pci.p_os_data); | ||
826 | |||
827 | if (err) { | ||
828 | phr->error = HPI_ERROR_INVALID_DATASIZE; | ||
829 | phw->outstream_host_buffer_size[phm->obj_index] = 0; | ||
830 | return; | ||
831 | } | ||
832 | |||
833 | err = hpios_locked_mem_get_phys_addr | ||
834 | (&phw->outstream_host_buffers[phm->obj_index], | ||
835 | &phm->u.d.u.buffer.pci_address); | ||
836 | /* get the phys addr into msg for single call alloc caller | ||
837 | * needs to do this for split alloc (or use the same message) | ||
838 | * return the phy address for split alloc in the respose too | ||
839 | */ | ||
840 | phr->u.d.u.stream_info.auxiliary_data_available = | ||
841 | phm->u.d.u.buffer.pci_address; | ||
842 | |||
843 | if (err) { | ||
844 | hpios_locked_mem_free(&phw->outstream_host_buffers | ||
845 | [phm->obj_index]); | ||
846 | phw->outstream_host_buffer_size[phm->obj_index] = 0; | ||
847 | phr->error = HPI_ERROR_MEMORY_ALLOC; | ||
848 | return; | ||
849 | } | ||
850 | } | ||
851 | |||
852 | if (command == HPI_BUFFER_CMD_EXTERNAL | ||
853 | || command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) { | ||
854 | /* GRANT phase. Set up the BBM status, tell the DSP about | ||
855 | the buffer so it can start using BBM. | ||
856 | */ | ||
857 | struct hpi_hostbuffer_status *status; | ||
858 | |||
859 | if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer. | ||
860 | buffer_size - 1)) { | ||
861 | HPI_DEBUG_LOG(ERROR, | ||
862 | "buffer size must be 2^N not %d\n", | ||
863 | phm->u.d.u.buffer.buffer_size); | ||
864 | phr->error = HPI_ERROR_INVALID_DATASIZE; | ||
865 | return; | ||
866 | } | ||
867 | phw->outstream_host_buffer_size[phm->obj_index] = | ||
868 | phm->u.d.u.buffer.buffer_size; | ||
869 | status = &interface->outstream_host_buffer_status[phm-> | ||
870 | obj_index]; | ||
871 | status->samples_processed = 0; | ||
872 | status->stream_state = HPI_STATE_STOPPED; | ||
873 | status->dSP_index = 0; | ||
874 | status->host_index = status->dSP_index; | ||
875 | status->size_in_bytes = phm->u.d.u.buffer.buffer_size; | ||
876 | |||
877 | hw_message(pao, phm, phr); | ||
878 | |||
879 | if (phr->error | ||
880 | && hpios_locked_mem_valid(&phw-> | ||
881 | outstream_host_buffers[phm->obj_index])) { | ||
882 | hpios_locked_mem_free(&phw->outstream_host_buffers | ||
883 | [phm->obj_index]); | ||
884 | phw->outstream_host_buffer_size[phm->obj_index] = 0; | ||
885 | } | ||
886 | } | ||
887 | } | ||
888 | |||
889 | static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao, | ||
890 | struct hpi_message *phm, struct hpi_response *phr) | ||
891 | { | ||
892 | struct hpi_hw_obj *phw = pao->priv; | ||
893 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
894 | struct hpi_hostbuffer_status *status; | ||
895 | u8 *p_bbm_data; | ||
896 | |||
897 | if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm-> | ||
898 | obj_index])) { | ||
899 | if (hpios_locked_mem_get_virt_addr(&phw-> | ||
900 | outstream_host_buffers[phm->obj_index], | ||
901 | (void *)&p_bbm_data)) { | ||
902 | phr->error = HPI_ERROR_INVALID_OPERATION; | ||
903 | return; | ||
904 | } | ||
905 | status = &interface->outstream_host_buffer_status[phm-> | ||
906 | obj_index]; | ||
907 | hpi_init_response(phr, HPI_OBJ_OSTREAM, | ||
908 | HPI_OSTREAM_HOSTBUFFER_GET_INFO, 0); | ||
909 | phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data; | ||
910 | phr->u.d.u.hostbuffer_info.p_status = status; | ||
911 | } else { | ||
912 | hpi_init_response(phr, HPI_OBJ_OSTREAM, | ||
913 | HPI_OSTREAM_HOSTBUFFER_GET_INFO, | ||
914 | HPI_ERROR_INVALID_OPERATION); | ||
915 | } | ||
916 | } | ||
917 | |||
918 | static void outstream_host_buffer_free(struct hpi_adapter_obj *pao, | ||
919 | struct hpi_message *phm, struct hpi_response *phr) | ||
920 | { | ||
921 | struct hpi_hw_obj *phw = pao->priv; | ||
922 | u32 command = phm->u.d.u.buffer.command; | ||
923 | |||
924 | if (phw->outstream_host_buffer_size[phm->obj_index]) { | ||
925 | if (command == HPI_BUFFER_CMD_EXTERNAL | ||
926 | || command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) { | ||
927 | phw->outstream_host_buffer_size[phm->obj_index] = 0; | ||
928 | hw_message(pao, phm, phr); | ||
929 | /* Tell adapter to stop using the host buffer. */ | ||
930 | } | ||
931 | if (command == HPI_BUFFER_CMD_EXTERNAL | ||
932 | || command == HPI_BUFFER_CMD_INTERNAL_FREE) | ||
933 | hpios_locked_mem_free(&phw->outstream_host_buffers | ||
934 | [phm->obj_index]); | ||
935 | } | ||
936 | /* Should HPI_ERROR_INVALID_OPERATION be returned | ||
937 | if no host buffer is allocated? */ | ||
938 | else | ||
939 | hpi_init_response(phr, HPI_OBJ_OSTREAM, | ||
940 | HPI_OSTREAM_HOSTBUFFER_FREE, 0); | ||
941 | |||
942 | } | ||
943 | |||
944 | static long outstream_get_space_available(struct hpi_hostbuffer_status | ||
945 | *status) | ||
946 | { | ||
947 | return status->size_in_bytes - ((long)(status->host_index) - | ||
948 | (long)(status->dSP_index)); | ||
949 | } | ||
950 | |||
951 | static void outstream_write(struct hpi_adapter_obj *pao, | ||
952 | struct hpi_message *phm, struct hpi_response *phr) | ||
953 | { | ||
954 | struct hpi_hw_obj *phw = pao->priv; | ||
955 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
956 | struct hpi_hostbuffer_status *status; | ||
957 | long space_available; | ||
958 | |||
959 | if (!phw->outstream_host_buffer_size[phm->obj_index]) { | ||
960 | /* there is no BBM buffer, write via message */ | ||
961 | hw_message(pao, phm, phr); | ||
962 | return; | ||
963 | } | ||
964 | |||
965 | hpi_init_response(phr, phm->object, phm->function, 0); | ||
966 | status = &interface->outstream_host_buffer_status[phm->obj_index]; | ||
967 | |||
968 | if (phw->flag_outstream_just_reset[phm->obj_index]) { | ||
969 | /* Format can only change after reset. Must tell DSP. */ | ||
970 | u16 function = phm->function; | ||
971 | phw->flag_outstream_just_reset[phm->obj_index] = 0; | ||
972 | phm->function = HPI_OSTREAM_SET_FORMAT; | ||
973 | hw_message(pao, phm, phr); /* send the format to the DSP */ | ||
974 | phm->function = function; | ||
975 | if (phr->error) | ||
976 | return; | ||
977 | } | ||
978 | #if 1 | ||
979 | if (phw->flag_outstream_just_reset[phm->obj_index]) { | ||
980 | /* First OutStremWrite() call following reset will write data to the | ||
981 | adapter's buffers, reducing delay before stream can start | ||
982 | */ | ||
983 | int partial_write = 0; | ||
984 | unsigned int original_size = 0; | ||
985 | |||
986 | /* Send the first buffer to the DSP the old way. */ | ||
987 | /* Limit size of first transfer - */ | ||
988 | /* expect that this will not usually be triggered. */ | ||
989 | if (phm->u.d.u.data.data_size > HPI6205_SIZEOF_DATA) { | ||
990 | partial_write = 1; | ||
991 | original_size = phm->u.d.u.data.data_size; | ||
992 | phm->u.d.u.data.data_size = HPI6205_SIZEOF_DATA; | ||
993 | } | ||
994 | /* write it */ | ||
995 | phm->function = HPI_OSTREAM_WRITE; | ||
996 | hw_message(pao, phm, phr); | ||
997 | /* update status information that the DSP would typically | ||
998 | * update (and will update next time the DSP | ||
999 | * buffer update task reads data from the host BBM buffer) | ||
1000 | */ | ||
1001 | status->auxiliary_data_available = phm->u.d.u.data.data_size; | ||
1002 | status->host_index += phm->u.d.u.data.data_size; | ||
1003 | status->dSP_index += phm->u.d.u.data.data_size; | ||
1004 | |||
1005 | /* if we did a full write, we can return from here. */ | ||
1006 | if (!partial_write) | ||
1007 | return; | ||
1008 | |||
1009 | /* tweak buffer parameters and let the rest of the */ | ||
1010 | /* buffer land in internal BBM buffer */ | ||
1011 | phm->u.d.u.data.data_size = | ||
1012 | original_size - HPI6205_SIZEOF_DATA; | ||
1013 | phm->u.d.u.data.pb_data += HPI6205_SIZEOF_DATA; | ||
1014 | } | ||
1015 | #endif | ||
1016 | |||
1017 | space_available = outstream_get_space_available(status); | ||
1018 | if (space_available < (long)phm->u.d.u.data.data_size) { | ||
1019 | phr->error = HPI_ERROR_INVALID_DATASIZE; | ||
1020 | return; | ||
1021 | } | ||
1022 | |||
1023 | /* HostBuffers is used to indicate host buffer is internally allocated. | ||
1024 | otherwise, assumed external, data written externally */ | ||
1025 | if (phm->u.d.u.data.pb_data | ||
1026 | && hpios_locked_mem_valid(&phw->outstream_host_buffers[phm-> | ||
1027 | obj_index])) { | ||
1028 | u8 *p_bbm_data; | ||
1029 | long l_first_write; | ||
1030 | u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data; | ||
1031 | |||
1032 | if (hpios_locked_mem_get_virt_addr(&phw-> | ||
1033 | outstream_host_buffers[phm->obj_index], | ||
1034 | (void *)&p_bbm_data)) { | ||
1035 | phr->error = HPI_ERROR_INVALID_OPERATION; | ||
1036 | return; | ||
1037 | } | ||
1038 | |||
1039 | /* either all data, | ||
1040 | or enough to fit from current to end of BBM buffer */ | ||
1041 | l_first_write = | ||
1042 | min(phm->u.d.u.data.data_size, | ||
1043 | status->size_in_bytes - | ||
1044 | (status->host_index & (status->size_in_bytes - 1))); | ||
1045 | |||
1046 | memcpy(p_bbm_data + | ||
1047 | (status->host_index & (status->size_in_bytes - 1)), | ||
1048 | p_app_data, l_first_write); | ||
1049 | /* remaining data if any */ | ||
1050 | memcpy(p_bbm_data, p_app_data + l_first_write, | ||
1051 | phm->u.d.u.data.data_size - l_first_write); | ||
1052 | } | ||
1053 | status->host_index += phm->u.d.u.data.data_size; | ||
1054 | } | ||
1055 | |||
1056 | static void outstream_get_info(struct hpi_adapter_obj *pao, | ||
1057 | struct hpi_message *phm, struct hpi_response *phr) | ||
1058 | { | ||
1059 | struct hpi_hw_obj *phw = pao->priv; | ||
1060 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
1061 | struct hpi_hostbuffer_status *status; | ||
1062 | |||
1063 | if (!phw->outstream_host_buffer_size[phm->obj_index]) { | ||
1064 | hw_message(pao, phm, phr); | ||
1065 | return; | ||
1066 | } | ||
1067 | |||
1068 | hpi_init_response(phr, phm->object, phm->function, 0); | ||
1069 | |||
1070 | status = &interface->outstream_host_buffer_status[phm->obj_index]; | ||
1071 | |||
1072 | phr->u.d.u.stream_info.state = (u16)status->stream_state; | ||
1073 | phr->u.d.u.stream_info.samples_transferred = | ||
1074 | status->samples_processed; | ||
1075 | phr->u.d.u.stream_info.buffer_size = status->size_in_bytes; | ||
1076 | phr->u.d.u.stream_info.data_available = | ||
1077 | status->size_in_bytes - outstream_get_space_available(status); | ||
1078 | phr->u.d.u.stream_info.auxiliary_data_available = | ||
1079 | status->auxiliary_data_available; | ||
1080 | } | ||
1081 | |||
1082 | static void outstream_start(struct hpi_adapter_obj *pao, | ||
1083 | struct hpi_message *phm, struct hpi_response *phr) | ||
1084 | { | ||
1085 | hw_message(pao, phm, phr); | ||
1086 | } | ||
1087 | |||
1088 | static void outstream_reset(struct hpi_adapter_obj *pao, | ||
1089 | struct hpi_message *phm, struct hpi_response *phr) | ||
1090 | { | ||
1091 | struct hpi_hw_obj *phw = pao->priv; | ||
1092 | phw->flag_outstream_just_reset[phm->obj_index] = 1; | ||
1093 | hw_message(pao, phm, phr); | ||
1094 | } | ||
1095 | |||
1096 | static void outstream_open(struct hpi_adapter_obj *pao, | ||
1097 | struct hpi_message *phm, struct hpi_response *phr) | ||
1098 | { | ||
1099 | outstream_reset(pao, phm, phr); | ||
1100 | } | ||
1101 | |||
1102 | /*****************************************************************************/ | ||
1103 | /* InStream Host buffer functions */ | ||
1104 | |||
1105 | static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao, | ||
1106 | struct hpi_message *phm, struct hpi_response *phr) | ||
1107 | { | ||
1108 | u16 err = 0; | ||
1109 | u32 command = phm->u.d.u.buffer.command; | ||
1110 | struct hpi_hw_obj *phw = pao->priv; | ||
1111 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
1112 | |||
1113 | hpi_init_response(phr, phm->object, phm->function, 0); | ||
1114 | |||
1115 | if (command == HPI_BUFFER_CMD_EXTERNAL | ||
1116 | || command == HPI_BUFFER_CMD_INTERNAL_ALLOC) { | ||
1117 | |||
1118 | phm->u.d.u.buffer.buffer_size = | ||
1119 | roundup_pow_of_two(phm->u.d.u.buffer.buffer_size); | ||
1120 | phr->u.d.u.stream_info.data_available = | ||
1121 | phw->instream_host_buffer_size[phm->obj_index]; | ||
1122 | phr->u.d.u.stream_info.buffer_size = | ||
1123 | phm->u.d.u.buffer.buffer_size; | ||
1124 | |||
1125 | if (phw->instream_host_buffer_size[phm->obj_index] == | ||
1126 | phm->u.d.u.buffer.buffer_size) { | ||
1127 | /* Same size, no action required */ | ||
1128 | return; | ||
1129 | } | ||
1130 | |||
1131 | if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm-> | ||
1132 | obj_index])) | ||
1133 | hpios_locked_mem_free(&phw->instream_host_buffers | ||
1134 | [phm->obj_index]); | ||
1135 | |||
1136 | err = hpios_locked_mem_alloc(&phw->instream_host_buffers[phm-> | ||
1137 | obj_index], phm->u.d.u.buffer.buffer_size, | ||
1138 | pao->pci.p_os_data); | ||
1139 | |||
1140 | if (err) { | ||
1141 | phr->error = HPI_ERROR_INVALID_DATASIZE; | ||
1142 | phw->instream_host_buffer_size[phm->obj_index] = 0; | ||
1143 | return; | ||
1144 | } | ||
1145 | |||
1146 | err = hpios_locked_mem_get_phys_addr | ||
1147 | (&phw->instream_host_buffers[phm->obj_index], | ||
1148 | &phm->u.d.u.buffer.pci_address); | ||
1149 | /* get the phys addr into msg for single call alloc. Caller | ||
1150 | needs to do this for split alloc so return the phy address */ | ||
1151 | phr->u.d.u.stream_info.auxiliary_data_available = | ||
1152 | phm->u.d.u.buffer.pci_address; | ||
1153 | if (err) { | ||
1154 | hpios_locked_mem_free(&phw->instream_host_buffers | ||
1155 | [phm->obj_index]); | ||
1156 | phw->instream_host_buffer_size[phm->obj_index] = 0; | ||
1157 | phr->error = HPI_ERROR_MEMORY_ALLOC; | ||
1158 | return; | ||
1159 | } | ||
1160 | } | ||
1161 | |||
1162 | if (command == HPI_BUFFER_CMD_EXTERNAL | ||
1163 | || command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) { | ||
1164 | struct hpi_hostbuffer_status *status; | ||
1165 | |||
1166 | if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer. | ||
1167 | buffer_size - 1)) { | ||
1168 | HPI_DEBUG_LOG(ERROR, | ||
1169 | "buffer size must be 2^N not %d\n", | ||
1170 | phm->u.d.u.buffer.buffer_size); | ||
1171 | phr->error = HPI_ERROR_INVALID_DATASIZE; | ||
1172 | return; | ||
1173 | } | ||
1174 | |||
1175 | phw->instream_host_buffer_size[phm->obj_index] = | ||
1176 | phm->u.d.u.buffer.buffer_size; | ||
1177 | status = &interface->instream_host_buffer_status[phm-> | ||
1178 | obj_index]; | ||
1179 | status->samples_processed = 0; | ||
1180 | status->stream_state = HPI_STATE_STOPPED; | ||
1181 | status->dSP_index = 0; | ||
1182 | status->host_index = status->dSP_index; | ||
1183 | status->size_in_bytes = phm->u.d.u.buffer.buffer_size; | ||
1184 | |||
1185 | hw_message(pao, phm, phr); | ||
1186 | if (phr->error | ||
1187 | && hpios_locked_mem_valid(&phw-> | ||
1188 | instream_host_buffers[phm->obj_index])) { | ||
1189 | hpios_locked_mem_free(&phw->instream_host_buffers | ||
1190 | [phm->obj_index]); | ||
1191 | phw->instream_host_buffer_size[phm->obj_index] = 0; | ||
1192 | } | ||
1193 | } | ||
1194 | } | ||
1195 | |||
1196 | static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao, | ||
1197 | struct hpi_message *phm, struct hpi_response *phr) | ||
1198 | { | ||
1199 | struct hpi_hw_obj *phw = pao->priv; | ||
1200 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
1201 | struct hpi_hostbuffer_status *status; | ||
1202 | u8 *p_bbm_data; | ||
1203 | |||
1204 | if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm-> | ||
1205 | obj_index])) { | ||
1206 | if (hpios_locked_mem_get_virt_addr(&phw-> | ||
1207 | instream_host_buffers[phm->obj_index], | ||
1208 | (void *)&p_bbm_data)) { | ||
1209 | phr->error = HPI_ERROR_INVALID_OPERATION; | ||
1210 | return; | ||
1211 | } | ||
1212 | status = &interface->instream_host_buffer_status[phm-> | ||
1213 | obj_index]; | ||
1214 | hpi_init_response(phr, HPI_OBJ_ISTREAM, | ||
1215 | HPI_ISTREAM_HOSTBUFFER_GET_INFO, 0); | ||
1216 | phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data; | ||
1217 | phr->u.d.u.hostbuffer_info.p_status = status; | ||
1218 | } else { | ||
1219 | hpi_init_response(phr, HPI_OBJ_ISTREAM, | ||
1220 | HPI_ISTREAM_HOSTBUFFER_GET_INFO, | ||
1221 | HPI_ERROR_INVALID_OPERATION); | ||
1222 | } | ||
1223 | } | ||
1224 | |||
1225 | static void instream_host_buffer_free(struct hpi_adapter_obj *pao, | ||
1226 | struct hpi_message *phm, struct hpi_response *phr) | ||
1227 | { | ||
1228 | struct hpi_hw_obj *phw = pao->priv; | ||
1229 | u32 command = phm->u.d.u.buffer.command; | ||
1230 | |||
1231 | if (phw->instream_host_buffer_size[phm->obj_index]) { | ||
1232 | if (command == HPI_BUFFER_CMD_EXTERNAL | ||
1233 | || command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) { | ||
1234 | phw->instream_host_buffer_size[phm->obj_index] = 0; | ||
1235 | hw_message(pao, phm, phr); | ||
1236 | } | ||
1237 | |||
1238 | if (command == HPI_BUFFER_CMD_EXTERNAL | ||
1239 | || command == HPI_BUFFER_CMD_INTERNAL_FREE) | ||
1240 | hpios_locked_mem_free(&phw->instream_host_buffers | ||
1241 | [phm->obj_index]); | ||
1242 | |||
1243 | } else { | ||
1244 | /* Should HPI_ERROR_INVALID_OPERATION be returned | ||
1245 | if no host buffer is allocated? */ | ||
1246 | hpi_init_response(phr, HPI_OBJ_ISTREAM, | ||
1247 | HPI_ISTREAM_HOSTBUFFER_FREE, 0); | ||
1248 | |||
1249 | } | ||
1250 | |||
1251 | } | ||
1252 | |||
1253 | static void instream_start(struct hpi_adapter_obj *pao, | ||
1254 | struct hpi_message *phm, struct hpi_response *phr) | ||
1255 | { | ||
1256 | hw_message(pao, phm, phr); | ||
1257 | } | ||
1258 | |||
1259 | static long instream_get_bytes_available(struct hpi_hostbuffer_status *status) | ||
1260 | { | ||
1261 | return (long)(status->dSP_index) - (long)(status->host_index); | ||
1262 | } | ||
1263 | |||
1264 | static void instream_read(struct hpi_adapter_obj *pao, | ||
1265 | struct hpi_message *phm, struct hpi_response *phr) | ||
1266 | { | ||
1267 | struct hpi_hw_obj *phw = pao->priv; | ||
1268 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
1269 | struct hpi_hostbuffer_status *status; | ||
1270 | long data_available; | ||
1271 | u8 *p_bbm_data; | ||
1272 | long l_first_read; | ||
1273 | u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data; | ||
1274 | |||
1275 | if (!phw->instream_host_buffer_size[phm->obj_index]) { | ||
1276 | hw_message(pao, phm, phr); | ||
1277 | return; | ||
1278 | } | ||
1279 | hpi_init_response(phr, phm->object, phm->function, 0); | ||
1280 | |||
1281 | status = &interface->instream_host_buffer_status[phm->obj_index]; | ||
1282 | data_available = instream_get_bytes_available(status); | ||
1283 | if (data_available < (long)phm->u.d.u.data.data_size) { | ||
1284 | phr->error = HPI_ERROR_INVALID_DATASIZE; | ||
1285 | return; | ||
1286 | } | ||
1287 | |||
1288 | if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm-> | ||
1289 | obj_index])) { | ||
1290 | if (hpios_locked_mem_get_virt_addr(&phw-> | ||
1291 | instream_host_buffers[phm->obj_index], | ||
1292 | (void *)&p_bbm_data)) { | ||
1293 | phr->error = HPI_ERROR_INVALID_OPERATION; | ||
1294 | return; | ||
1295 | } | ||
1296 | |||
1297 | /* either all data, | ||
1298 | or enough to fit from current to end of BBM buffer */ | ||
1299 | l_first_read = | ||
1300 | min(phm->u.d.u.data.data_size, | ||
1301 | status->size_in_bytes - | ||
1302 | (status->host_index & (status->size_in_bytes - 1))); | ||
1303 | |||
1304 | memcpy(p_app_data, | ||
1305 | p_bbm_data + | ||
1306 | (status->host_index & (status->size_in_bytes - 1)), | ||
1307 | l_first_read); | ||
1308 | /* remaining data if any */ | ||
1309 | memcpy(p_app_data + l_first_read, p_bbm_data, | ||
1310 | phm->u.d.u.data.data_size - l_first_read); | ||
1311 | } | ||
1312 | status->host_index += phm->u.d.u.data.data_size; | ||
1313 | } | ||
1314 | |||
1315 | static void instream_get_info(struct hpi_adapter_obj *pao, | ||
1316 | struct hpi_message *phm, struct hpi_response *phr) | ||
1317 | { | ||
1318 | struct hpi_hw_obj *phw = pao->priv; | ||
1319 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
1320 | struct hpi_hostbuffer_status *status; | ||
1321 | if (!phw->instream_host_buffer_size[phm->obj_index]) { | ||
1322 | hw_message(pao, phm, phr); | ||
1323 | return; | ||
1324 | } | ||
1325 | |||
1326 | status = &interface->instream_host_buffer_status[phm->obj_index]; | ||
1327 | |||
1328 | hpi_init_response(phr, phm->object, phm->function, 0); | ||
1329 | |||
1330 | phr->u.d.u.stream_info.state = (u16)status->stream_state; | ||
1331 | phr->u.d.u.stream_info.samples_transferred = | ||
1332 | status->samples_processed; | ||
1333 | phr->u.d.u.stream_info.buffer_size = status->size_in_bytes; | ||
1334 | phr->u.d.u.stream_info.data_available = | ||
1335 | instream_get_bytes_available(status); | ||
1336 | phr->u.d.u.stream_info.auxiliary_data_available = | ||
1337 | status->auxiliary_data_available; | ||
1338 | } | ||
1339 | |||
1340 | /*****************************************************************************/ | ||
1341 | /* LOW-LEVEL */ | ||
1342 | #define HPI6205_MAX_FILES_TO_LOAD 2 | ||
1343 | |||
1344 | static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, | ||
1345 | u32 *pos_error_code) | ||
1346 | { | ||
1347 | struct hpi_hw_obj *phw = pao->priv; | ||
1348 | struct dsp_code dsp_code; | ||
1349 | u16 boot_code_id[HPI6205_MAX_FILES_TO_LOAD]; | ||
1350 | u16 firmware_id = pao->pci.subsys_device_id; | ||
1351 | u32 temp; | ||
1352 | int dsp = 0, i = 0; | ||
1353 | u16 err = 0; | ||
1354 | |||
1355 | boot_code_id[0] = HPI_ADAPTER_ASI(0x6205); | ||
1356 | |||
1357 | /* special cases where firmware_id != subsys ID */ | ||
1358 | switch (firmware_id) { | ||
1359 | case HPI_ADAPTER_FAMILY_ASI(0x5000): | ||
1360 | boot_code_id[0] = firmware_id; | ||
1361 | firmware_id = 0; | ||
1362 | break; | ||
1363 | case HPI_ADAPTER_FAMILY_ASI(0x5300): | ||
1364 | case HPI_ADAPTER_FAMILY_ASI(0x5400): | ||
1365 | case HPI_ADAPTER_FAMILY_ASI(0x6300): | ||
1366 | firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6400); | ||
1367 | break; | ||
1368 | case HPI_ADAPTER_FAMILY_ASI(0x5600): | ||
1369 | case HPI_ADAPTER_FAMILY_ASI(0x6500): | ||
1370 | firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6600); | ||
1371 | break; | ||
1372 | } | ||
1373 | boot_code_id[1] = firmware_id; | ||
1374 | |||
1375 | /* reset DSP by writing a 1 to the WARMRESET bit */ | ||
1376 | temp = C6205_HDCR_WARMRESET; | ||
1377 | iowrite32(temp, phw->prHDCR); | ||
1378 | hpios_delay_micro_seconds(1000); | ||
1379 | |||
1380 | /* check that PCI i/f was configured by EEPROM */ | ||
1381 | temp = ioread32(phw->prHSR); | ||
1382 | if ((temp & (C6205_HSR_CFGERR | C6205_HSR_EEREAD)) != | ||
1383 | C6205_HSR_EEREAD) | ||
1384 | return hpi6205_error(0, HPI6205_ERROR_6205_EEPROM); | ||
1385 | temp |= 0x04; | ||
1386 | /* disable PINTA interrupt */ | ||
1387 | iowrite32(temp, phw->prHSR); | ||
1388 | |||
1389 | /* check control register reports PCI boot mode */ | ||
1390 | temp = ioread32(phw->prHDCR); | ||
1391 | if (!(temp & C6205_HDCR_PCIBOOT)) | ||
1392 | return hpi6205_error(0, HPI6205_ERROR_6205_REG); | ||
1393 | |||
1394 | /* try writing a couple of numbers to the DSP page register */ | ||
1395 | /* and reading them back. */ | ||
1396 | temp = 1; | ||
1397 | iowrite32(temp, phw->prDSPP); | ||
1398 | if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP)) | ||
1399 | return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE); | ||
1400 | temp = 2; | ||
1401 | iowrite32(temp, phw->prDSPP); | ||
1402 | if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP)) | ||
1403 | return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE); | ||
1404 | temp = 3; | ||
1405 | iowrite32(temp, phw->prDSPP); | ||
1406 | if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP)) | ||
1407 | return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE); | ||
1408 | /* reset DSP page to the correct number */ | ||
1409 | temp = 0; | ||
1410 | iowrite32(temp, phw->prDSPP); | ||
1411 | if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP)) | ||
1412 | return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE); | ||
1413 | phw->dsp_page = 0; | ||
1414 | |||
1415 | /* release 6713 from reset before 6205 is bootloaded. | ||
1416 | This ensures that the EMIF is inactive, | ||
1417 | and the 6713 HPI gets the correct bootmode etc | ||
1418 | */ | ||
1419 | if (boot_code_id[1] != 0) { | ||
1420 | /* DSP 1 is a C6713 */ | ||
1421 | /* CLKX0 <- '1' release the C6205 bootmode pulldowns */ | ||
1422 | boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202); | ||
1423 | hpios_delay_micro_seconds(100); | ||
1424 | /* Reset the 6713 #1 - revB */ | ||
1425 | boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0); | ||
1426 | |||
1427 | /* dummy read every 4 words for 6205 advisory 1.4.4 */ | ||
1428 | boot_loader_read_mem32(pao, 0, 0); | ||
1429 | |||
1430 | hpios_delay_micro_seconds(100); | ||
1431 | /* Release C6713 from reset - revB */ | ||
1432 | boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4); | ||
1433 | hpios_delay_micro_seconds(100); | ||
1434 | } | ||
1435 | |||
1436 | for (dsp = 0; dsp < HPI6205_MAX_FILES_TO_LOAD; dsp++) { | ||
1437 | /* is there a DSP to load? */ | ||
1438 | if (boot_code_id[dsp] == 0) | ||
1439 | continue; | ||
1440 | |||
1441 | err = boot_loader_config_emif(pao, dsp); | ||
1442 | if (err) | ||
1443 | return err; | ||
1444 | |||
1445 | err = boot_loader_test_internal_memory(pao, dsp); | ||
1446 | if (err) | ||
1447 | return err; | ||
1448 | |||
1449 | err = boot_loader_test_external_memory(pao, dsp); | ||
1450 | if (err) | ||
1451 | return err; | ||
1452 | |||
1453 | err = boot_loader_test_pld(pao, dsp); | ||
1454 | if (err) | ||
1455 | return err; | ||
1456 | |||
1457 | /* write the DSP code down into the DSPs memory */ | ||
1458 | dsp_code.ps_dev = pao->pci.p_os_data; | ||
1459 | err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code, | ||
1460 | pos_error_code); | ||
1461 | if (err) | ||
1462 | return err; | ||
1463 | |||
1464 | while (1) { | ||
1465 | u32 length; | ||
1466 | u32 address; | ||
1467 | u32 type; | ||
1468 | u32 *pcode; | ||
1469 | |||
1470 | err = hpi_dsp_code_read_word(&dsp_code, &length); | ||
1471 | if (err) | ||
1472 | break; | ||
1473 | if (length == 0xFFFFFFFF) | ||
1474 | break; /* end of code */ | ||
1475 | |||
1476 | err = hpi_dsp_code_read_word(&dsp_code, &address); | ||
1477 | if (err) | ||
1478 | break; | ||
1479 | err = hpi_dsp_code_read_word(&dsp_code, &type); | ||
1480 | if (err) | ||
1481 | break; | ||
1482 | err = hpi_dsp_code_read_block(length, &dsp_code, | ||
1483 | &pcode); | ||
1484 | if (err) | ||
1485 | break; | ||
1486 | for (i = 0; i < (int)length; i++) { | ||
1487 | err = boot_loader_write_mem32(pao, dsp, | ||
1488 | address, *pcode); | ||
1489 | if (err) | ||
1490 | break; | ||
1491 | /* dummy read every 4 words */ | ||
1492 | /* for 6205 advisory 1.4.4 */ | ||
1493 | if (i % 4 == 0) | ||
1494 | boot_loader_read_mem32(pao, dsp, | ||
1495 | address); | ||
1496 | pcode++; | ||
1497 | address += 4; | ||
1498 | } | ||
1499 | |||
1500 | } | ||
1501 | if (err) { | ||
1502 | hpi_dsp_code_close(&dsp_code); | ||
1503 | return err; | ||
1504 | } | ||
1505 | |||
1506 | /* verify code */ | ||
1507 | hpi_dsp_code_rewind(&dsp_code); | ||
1508 | while (1) { | ||
1509 | u32 length = 0; | ||
1510 | u32 address = 0; | ||
1511 | u32 type = 0; | ||
1512 | u32 *pcode = NULL; | ||
1513 | u32 data = 0; | ||
1514 | |||
1515 | hpi_dsp_code_read_word(&dsp_code, &length); | ||
1516 | if (length == 0xFFFFFFFF) | ||
1517 | break; /* end of code */ | ||
1518 | |||
1519 | hpi_dsp_code_read_word(&dsp_code, &address); | ||
1520 | hpi_dsp_code_read_word(&dsp_code, &type); | ||
1521 | hpi_dsp_code_read_block(length, &dsp_code, &pcode); | ||
1522 | |||
1523 | for (i = 0; i < (int)length; i++) { | ||
1524 | data = boot_loader_read_mem32(pao, dsp, | ||
1525 | address); | ||
1526 | if (data != *pcode) { | ||
1527 | err = 0; | ||
1528 | break; | ||
1529 | } | ||
1530 | pcode++; | ||
1531 | address += 4; | ||
1532 | } | ||
1533 | if (err) | ||
1534 | break; | ||
1535 | } | ||
1536 | hpi_dsp_code_close(&dsp_code); | ||
1537 | if (err) | ||
1538 | return err; | ||
1539 | } | ||
1540 | |||
1541 | /* After bootloading all DSPs, start DSP0 running | ||
1542 | * The DSP0 code will handle starting and synchronizing with its slaves | ||
1543 | */ | ||
1544 | if (phw->p_interface_buffer) { | ||
1545 | /* we need to tell the card the physical PCI address */ | ||
1546 | u32 physicalPC_iaddress; | ||
1547 | struct bus_master_interface *interface = | ||
1548 | phw->p_interface_buffer; | ||
1549 | u32 host_mailbox_address_on_dsp; | ||
1550 | u32 physicalPC_iaddress_verify = 0; | ||
1551 | int time_out = 10; | ||
1552 | /* set ack so we know when DSP is ready to go */ | ||
1553 | /* (dwDspAck will be changed to HIF_RESET) */ | ||
1554 | interface->dsp_ack = H620_HIF_UNKNOWN; | ||
1555 | wmb(); /* ensure ack is written before dsp writes back */ | ||
1556 | |||
1557 | err = hpios_locked_mem_get_phys_addr(&phw->h_locked_mem, | ||
1558 | &physicalPC_iaddress); | ||
1559 | |||
1560 | /* locate the host mailbox on the DSP. */ | ||
1561 | host_mailbox_address_on_dsp = 0x80000000; | ||
1562 | while ((physicalPC_iaddress != physicalPC_iaddress_verify) | ||
1563 | && time_out--) { | ||
1564 | err = boot_loader_write_mem32(pao, 0, | ||
1565 | host_mailbox_address_on_dsp, | ||
1566 | physicalPC_iaddress); | ||
1567 | physicalPC_iaddress_verify = | ||
1568 | boot_loader_read_mem32(pao, 0, | ||
1569 | host_mailbox_address_on_dsp); | ||
1570 | } | ||
1571 | } | ||
1572 | HPI_DEBUG_LOG(DEBUG, "starting DS_ps running\n"); | ||
1573 | /* enable interrupts */ | ||
1574 | temp = ioread32(phw->prHSR); | ||
1575 | temp &= ~(u32)C6205_HSR_INTAM; | ||
1576 | iowrite32(temp, phw->prHSR); | ||
1577 | |||
1578 | /* start code running... */ | ||
1579 | temp = ioread32(phw->prHDCR); | ||
1580 | temp |= (u32)C6205_HDCR_DSPINT; | ||
1581 | iowrite32(temp, phw->prHDCR); | ||
1582 | |||
1583 | /* give the DSP 10ms to start up */ | ||
1584 | hpios_delay_micro_seconds(10000); | ||
1585 | return err; | ||
1586 | |||
1587 | } | ||
1588 | |||
1589 | /*****************************************************************************/ | ||
1590 | /* Bootloader utility functions */ | ||
1591 | |||
1592 | static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index, | ||
1593 | u32 address) | ||
1594 | { | ||
1595 | struct hpi_hw_obj *phw = pao->priv; | ||
1596 | u32 data = 0; | ||
1597 | __iomem u32 *p_data; | ||
1598 | |||
1599 | if (dsp_index == 0) { | ||
1600 | /* DSP 0 is always C6205 */ | ||
1601 | if ((address >= 0x01800000) & (address < 0x02000000)) { | ||
1602 | /* BAR1 register access */ | ||
1603 | p_data = pao->pci.ap_mem_base[1] + | ||
1604 | (address & 0x007fffff) / | ||
1605 | sizeof(*pao->pci.ap_mem_base[1]); | ||
1606 | /* HPI_DEBUG_LOG(WARNING, | ||
1607 | "BAR1 access %08x\n", dwAddress); */ | ||
1608 | } else { | ||
1609 | u32 dw4M_page = address >> 22L; | ||
1610 | if (dw4M_page != phw->dsp_page) { | ||
1611 | phw->dsp_page = dw4M_page; | ||
1612 | /* *INDENT OFF* */ | ||
1613 | iowrite32(phw->dsp_page, phw->prDSPP); | ||
1614 | /* *INDENT-ON* */ | ||
1615 | } | ||
1616 | address &= 0x3fffff; /* address within 4M page */ | ||
1617 | /* BAR0 memory access */ | ||
1618 | p_data = pao->pci.ap_mem_base[0] + | ||
1619 | address / sizeof(u32); | ||
1620 | } | ||
1621 | data = ioread32(p_data); | ||
1622 | } else if (dsp_index == 1) { | ||
1623 | /* DSP 1 is a C6713 */ | ||
1624 | u32 lsb; | ||
1625 | boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address); | ||
1626 | boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16); | ||
1627 | lsb = boot_loader_read_mem32(pao, 0, HPIDL_ADDR); | ||
1628 | data = boot_loader_read_mem32(pao, 0, HPIDH_ADDR); | ||
1629 | data = (data << 16) | (lsb & 0xFFFF); | ||
1630 | } | ||
1631 | return data; | ||
1632 | } | ||
1633 | |||
1634 | static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index, | ||
1635 | u32 address, u32 data) | ||
1636 | { | ||
1637 | struct hpi_hw_obj *phw = pao->priv; | ||
1638 | u16 err = 0; | ||
1639 | __iomem u32 *p_data; | ||
1640 | /* u32 dwVerifyData=0; */ | ||
1641 | |||
1642 | if (dsp_index == 0) { | ||
1643 | /* DSP 0 is always C6205 */ | ||
1644 | if ((address >= 0x01800000) & (address < 0x02000000)) { | ||
1645 | /* BAR1 - DSP register access using */ | ||
1646 | /* Non-prefetchable PCI access */ | ||
1647 | p_data = pao->pci.ap_mem_base[1] + | ||
1648 | (address & 0x007fffff) / | ||
1649 | sizeof(*pao->pci.ap_mem_base[1]); | ||
1650 | } else { | ||
1651 | /* BAR0 access - all of DSP memory using */ | ||
1652 | /* pre-fetchable PCI access */ | ||
1653 | u32 dw4M_page = address >> 22L; | ||
1654 | if (dw4M_page != phw->dsp_page) { | ||
1655 | phw->dsp_page = dw4M_page; | ||
1656 | /* *INDENT-OFF* */ | ||
1657 | iowrite32(phw->dsp_page, phw->prDSPP); | ||
1658 | /* *INDENT-ON* */ | ||
1659 | } | ||
1660 | address &= 0x3fffff; /* address within 4M page */ | ||
1661 | p_data = pao->pci.ap_mem_base[0] + | ||
1662 | address / sizeof(u32); | ||
1663 | } | ||
1664 | iowrite32(data, p_data); | ||
1665 | } else if (dsp_index == 1) { | ||
1666 | /* DSP 1 is a C6713 */ | ||
1667 | boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address); | ||
1668 | boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16); | ||
1669 | |||
1670 | /* dummy read every 4 words for 6205 advisory 1.4.4 */ | ||
1671 | boot_loader_read_mem32(pao, 0, 0); | ||
1672 | |||
1673 | boot_loader_write_mem32(pao, 0, HPIDL_ADDR, data); | ||
1674 | boot_loader_write_mem32(pao, 0, HPIDH_ADDR, data >> 16); | ||
1675 | |||
1676 | /* dummy read every 4 words for 6205 advisory 1.4.4 */ | ||
1677 | boot_loader_read_mem32(pao, 0, 0); | ||
1678 | } else | ||
1679 | err = hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX); | ||
1680 | return err; | ||
1681 | } | ||
1682 | |||
1683 | static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index) | ||
1684 | { | ||
1685 | u16 err = 0; | ||
1686 | |||
1687 | if (dsp_index == 0) { | ||
1688 | u32 setting; | ||
1689 | |||
1690 | /* DSP 0 is always C6205 */ | ||
1691 | |||
1692 | /* Set the EMIF */ | ||
1693 | /* memory map of C6205 */ | ||
1694 | /* 00000000-0000FFFF 16Kx32 internal program */ | ||
1695 | /* 00400000-00BFFFFF CE0 2Mx32 SDRAM running @ 100MHz */ | ||
1696 | |||
1697 | /* EMIF config */ | ||
1698 | /*------------ */ | ||
1699 | /* Global EMIF control */ | ||
1700 | boot_loader_write_mem32(pao, dsp_index, 0x01800000, 0x3779); | ||
1701 | #define WS_OFS 28 | ||
1702 | #define WST_OFS 22 | ||
1703 | #define WH_OFS 20 | ||
1704 | #define RS_OFS 16 | ||
1705 | #define RST_OFS 8 | ||
1706 | #define MTYPE_OFS 4 | ||
1707 | #define RH_OFS 0 | ||
1708 | |||
1709 | /* EMIF CE0 setup - 2Mx32 Sync DRAM on ASI5000 cards only */ | ||
1710 | setting = 0x00000030; | ||
1711 | boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting); | ||
1712 | if (setting != boot_loader_read_mem32(pao, dsp_index, | ||
1713 | 0x01800008)) | ||
1714 | return hpi6205_error(dsp_index, | ||
1715 | HPI6205_ERROR_DSP_EMIF); | ||
1716 | |||
1717 | /* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */ | ||
1718 | /* which occupies D15..0. 6713 starts at 27MHz, so need */ | ||
1719 | /* plenty of wait states. See dsn8701.rtf, and 6713 errata. */ | ||
1720 | /* WST should be 71, but 63 is max possible */ | ||
1721 | setting = | ||
1722 | (1L << WS_OFS) | (63L << WST_OFS) | (1L << WH_OFS) | | ||
1723 | (1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) | | ||
1724 | (2L << MTYPE_OFS); | ||
1725 | boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting); | ||
1726 | if (setting != boot_loader_read_mem32(pao, dsp_index, | ||
1727 | 0x01800004)) | ||
1728 | return hpi6205_error(dsp_index, | ||
1729 | HPI6205_ERROR_DSP_EMIF); | ||
1730 | |||
1731 | /* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */ | ||
1732 | /* which occupies D15..0. 6713 starts at 27MHz, so need */ | ||
1733 | /* plenty of wait states */ | ||
1734 | setting = | ||
1735 | (1L << WS_OFS) | (28L << WST_OFS) | (1L << WH_OFS) | | ||
1736 | (1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) | | ||
1737 | (2L << MTYPE_OFS); | ||
1738 | boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting); | ||
1739 | if (setting != boot_loader_read_mem32(pao, dsp_index, | ||
1740 | 0x01800010)) | ||
1741 | return hpi6205_error(dsp_index, | ||
1742 | HPI6205_ERROR_DSP_EMIF); | ||
1743 | |||
1744 | /* EMIF CE3 setup - 32 bit async. */ | ||
1745 | /* This is the PLD on the ASI5000 cards only */ | ||
1746 | setting = | ||
1747 | (1L << WS_OFS) | (10L << WST_OFS) | (1L << WH_OFS) | | ||
1748 | (1L << RS_OFS) | (10L << RST_OFS) | (1L << RH_OFS) | | ||
1749 | (2L << MTYPE_OFS); | ||
1750 | boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting); | ||
1751 | if (setting != boot_loader_read_mem32(pao, dsp_index, | ||
1752 | 0x01800014)) | ||
1753 | return hpi6205_error(dsp_index, | ||
1754 | HPI6205_ERROR_DSP_EMIF); | ||
1755 | |||
1756 | /* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */ | ||
1757 | /* need to use this else DSP code crashes? */ | ||
1758 | boot_loader_write_mem32(pao, dsp_index, 0x01800018, | ||
1759 | 0x07117000); | ||
1760 | |||
1761 | /* EMIF SDRAM Refresh Timing */ | ||
1762 | /* EMIF SDRAM timing (orig = 0x410, emulator = 0x61a) */ | ||
1763 | boot_loader_write_mem32(pao, dsp_index, 0x0180001C, | ||
1764 | 0x00000410); | ||
1765 | |||
1766 | } else if (dsp_index == 1) { | ||
1767 | /* test access to the C6713s HPI registers */ | ||
1768 | u32 write_data = 0, read_data = 0, i = 0; | ||
1769 | |||
1770 | /* Set up HPIC for little endian, by setiing HPIC:HWOB=1 */ | ||
1771 | write_data = 1; | ||
1772 | boot_loader_write_mem32(pao, 0, HPICL_ADDR, write_data); | ||
1773 | boot_loader_write_mem32(pao, 0, HPICH_ADDR, write_data); | ||
1774 | /* C67 HPI is on lower 16bits of 32bit EMIF */ | ||
1775 | read_data = | ||
1776 | 0xFFF7 & boot_loader_read_mem32(pao, 0, HPICL_ADDR); | ||
1777 | if (write_data != read_data) { | ||
1778 | err = hpi6205_error(dsp_index, | ||
1779 | HPI6205_ERROR_C6713_HPIC); | ||
1780 | HPI_DEBUG_LOG(ERROR, "HPICL %x %x\n", write_data, | ||
1781 | read_data); | ||
1782 | |||
1783 | return err; | ||
1784 | } | ||
1785 | /* HPIA - walking ones test */ | ||
1786 | write_data = 1; | ||
1787 | for (i = 0; i < 32; i++) { | ||
1788 | boot_loader_write_mem32(pao, 0, HPIAL_ADDR, | ||
1789 | write_data); | ||
1790 | boot_loader_write_mem32(pao, 0, HPIAH_ADDR, | ||
1791 | (write_data >> 16)); | ||
1792 | read_data = | ||
1793 | 0xFFFF & boot_loader_read_mem32(pao, 0, | ||
1794 | HPIAL_ADDR); | ||
1795 | read_data = | ||
1796 | read_data | ((0xFFFF & | ||
1797 | boot_loader_read_mem32(pao, 0, | ||
1798 | HPIAH_ADDR)) | ||
1799 | << 16); | ||
1800 | if (read_data != write_data) { | ||
1801 | err = hpi6205_error(dsp_index, | ||
1802 | HPI6205_ERROR_C6713_HPIA); | ||
1803 | HPI_DEBUG_LOG(ERROR, "HPIA %x %x\n", | ||
1804 | write_data, read_data); | ||
1805 | return err; | ||
1806 | } | ||
1807 | write_data = write_data << 1; | ||
1808 | } | ||
1809 | |||
1810 | /* setup C67x PLL | ||
1811 | * ** C6713 datasheet says we cannot program PLL from HPI, | ||
1812 | * and indeed if we try to set the PLL multiply from the HPI, | ||
1813 | * the PLL does not seem to lock, so we enable the PLL and | ||
1814 | * use the default multiply of x 7, which for a 27MHz clock | ||
1815 | * gives a DSP speed of 189MHz | ||
1816 | */ | ||
1817 | /* bypass PLL */ | ||
1818 | boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0000); | ||
1819 | hpios_delay_micro_seconds(1000); | ||
1820 | /* EMIF = 189/3=63MHz */ | ||
1821 | boot_loader_write_mem32(pao, dsp_index, 0x01B7C120, 0x8002); | ||
1822 | /* peri = 189/2 */ | ||
1823 | boot_loader_write_mem32(pao, dsp_index, 0x01B7C11C, 0x8001); | ||
1824 | /* cpu = 189/1 */ | ||
1825 | boot_loader_write_mem32(pao, dsp_index, 0x01B7C118, 0x8000); | ||
1826 | hpios_delay_micro_seconds(1000); | ||
1827 | /* ** SGT test to take GPO3 high when we start the PLL */ | ||
1828 | /* and low when the delay is completed */ | ||
1829 | /* FSX0 <- '1' (GPO3) */ | ||
1830 | boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A0A); | ||
1831 | /* PLL not bypassed */ | ||
1832 | boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0001); | ||
1833 | hpios_delay_micro_seconds(1000); | ||
1834 | /* FSX0 <- '0' (GPO3) */ | ||
1835 | boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A02); | ||
1836 | |||
1837 | /* 6205 EMIF CE1 resetup - 32 bit async. */ | ||
1838 | /* Now 6713 #1 is running at 189MHz can reduce waitstates */ | ||
1839 | boot_loader_write_mem32(pao, 0, 0x01800004, /* CE1 */ | ||
1840 | (1L << WS_OFS) | (8L << WST_OFS) | (1L << WH_OFS) | | ||
1841 | (1L << RS_OFS) | (12L << RST_OFS) | (1L << RH_OFS) | | ||
1842 | (2L << MTYPE_OFS)); | ||
1843 | |||
1844 | hpios_delay_micro_seconds(1000); | ||
1845 | |||
1846 | /* check that we can read one of the PLL registers */ | ||
1847 | /* PLL should not be bypassed! */ | ||
1848 | if ((boot_loader_read_mem32(pao, dsp_index, 0x01B7C100) & 0xF) | ||
1849 | != 0x0001) { | ||
1850 | err = hpi6205_error(dsp_index, | ||
1851 | HPI6205_ERROR_C6713_PLL); | ||
1852 | return err; | ||
1853 | } | ||
1854 | /* setup C67x EMIF (note this is the only use of | ||
1855 | BAR1 via BootLoader_WriteMem32) */ | ||
1856 | boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_GCTL, | ||
1857 | 0x000034A8); | ||
1858 | boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_CE0, | ||
1859 | 0x00000030); | ||
1860 | boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMEXT, | ||
1861 | 0x001BDF29); | ||
1862 | boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMCTL, | ||
1863 | 0x47117000); | ||
1864 | boot_loader_write_mem32(pao, dsp_index, | ||
1865 | C6713_EMIF_SDRAMTIMING, 0x00000410); | ||
1866 | |||
1867 | hpios_delay_micro_seconds(1000); | ||
1868 | } else if (dsp_index == 2) { | ||
1869 | /* DSP 2 is a C6713 */ | ||
1870 | |||
1871 | } else | ||
1872 | err = hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX); | ||
1873 | return err; | ||
1874 | } | ||
1875 | |||
1876 | static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index, | ||
1877 | u32 start_address, u32 length) | ||
1878 | { | ||
1879 | u32 i = 0, j = 0; | ||
1880 | u32 test_addr = 0; | ||
1881 | u32 test_data = 0, data = 0; | ||
1882 | |||
1883 | length = 1000; | ||
1884 | |||
1885 | /* for 1st word, test each bit in the 32bit word, */ | ||
1886 | /* dwLength specifies number of 32bit words to test */ | ||
1887 | /*for(i=0; i<dwLength; i++) */ | ||
1888 | i = 0; | ||
1889 | { | ||
1890 | test_addr = start_address + i * 4; | ||
1891 | test_data = 0x00000001; | ||
1892 | for (j = 0; j < 32; j++) { | ||
1893 | boot_loader_write_mem32(pao, dsp_index, test_addr, | ||
1894 | test_data); | ||
1895 | data = boot_loader_read_mem32(pao, dsp_index, | ||
1896 | test_addr); | ||
1897 | if (data != test_data) { | ||
1898 | HPI_DEBUG_LOG(VERBOSE, | ||
1899 | "memtest error details " | ||
1900 | "%08x %08x %08x %i\n", test_addr, | ||
1901 | test_data, data, dsp_index); | ||
1902 | return 1; /* error */ | ||
1903 | } | ||
1904 | test_data = test_data << 1; | ||
1905 | } /* for(j) */ | ||
1906 | } /* for(i) */ | ||
1907 | |||
1908 | /* for the next 100 locations test each location, leaving it as zero */ | ||
1909 | /* write a zero to the next word in memory before we read */ | ||
1910 | /* the previous write to make sure every memory location is unique */ | ||
1911 | for (i = 0; i < 100; i++) { | ||
1912 | test_addr = start_address + i * 4; | ||
1913 | test_data = 0xA5A55A5A; | ||
1914 | boot_loader_write_mem32(pao, dsp_index, test_addr, test_data); | ||
1915 | boot_loader_write_mem32(pao, dsp_index, test_addr + 4, 0); | ||
1916 | data = boot_loader_read_mem32(pao, dsp_index, test_addr); | ||
1917 | if (data != test_data) { | ||
1918 | HPI_DEBUG_LOG(VERBOSE, | ||
1919 | "memtest error details " | ||
1920 | "%08x %08x %08x %i\n", test_addr, test_data, | ||
1921 | data, dsp_index); | ||
1922 | return 1; /* error */ | ||
1923 | } | ||
1924 | /* leave location as zero */ | ||
1925 | boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0); | ||
1926 | } | ||
1927 | |||
1928 | /* zero out entire memory block */ | ||
1929 | for (i = 0; i < length; i++) { | ||
1930 | test_addr = start_address + i * 4; | ||
1931 | boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0); | ||
1932 | } | ||
1933 | return 0; | ||
1934 | } | ||
1935 | |||
1936 | static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao, | ||
1937 | int dsp_index) | ||
1938 | { | ||
1939 | int err = 0; | ||
1940 | if (dsp_index == 0) { | ||
1941 | /* DSP 0 is a C6205 */ | ||
1942 | /* 64K prog mem */ | ||
1943 | err = boot_loader_test_memory(pao, dsp_index, 0x00000000, | ||
1944 | 0x10000); | ||
1945 | if (!err) | ||
1946 | /* 64K data mem */ | ||
1947 | err = boot_loader_test_memory(pao, dsp_index, | ||
1948 | 0x80000000, 0x10000); | ||
1949 | } else if ((dsp_index == 1) || (dsp_index == 2)) { | ||
1950 | /* DSP 1&2 are a C6713 */ | ||
1951 | /* 192K internal mem */ | ||
1952 | err = boot_loader_test_memory(pao, dsp_index, 0x00000000, | ||
1953 | 0x30000); | ||
1954 | if (!err) | ||
1955 | /* 64K internal mem / L2 cache */ | ||
1956 | err = boot_loader_test_memory(pao, dsp_index, | ||
1957 | 0x00030000, 0x10000); | ||
1958 | } else | ||
1959 | return hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX); | ||
1960 | |||
1961 | if (err) | ||
1962 | return hpi6205_error(dsp_index, HPI6205_ERROR_DSP_INTMEM); | ||
1963 | else | ||
1964 | return 0; | ||
1965 | } | ||
1966 | |||
1967 | static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao, | ||
1968 | int dsp_index) | ||
1969 | { | ||
1970 | u32 dRAM_start_address = 0; | ||
1971 | u32 dRAM_size = 0; | ||
1972 | |||
1973 | if (dsp_index == 0) { | ||
1974 | /* only test for SDRAM if an ASI5000 card */ | ||
1975 | if (pao->pci.subsys_device_id == 0x5000) { | ||
1976 | /* DSP 0 is always C6205 */ | ||
1977 | dRAM_start_address = 0x00400000; | ||
1978 | dRAM_size = 0x200000; | ||
1979 | /*dwDRAMinc=1024; */ | ||
1980 | } else | ||
1981 | return 0; | ||
1982 | } else if ((dsp_index == 1) || (dsp_index == 2)) { | ||
1983 | /* DSP 1 is a C6713 */ | ||
1984 | dRAM_start_address = 0x80000000; | ||
1985 | dRAM_size = 0x200000; | ||
1986 | /*dwDRAMinc=1024; */ | ||
1987 | } else | ||
1988 | return hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX); | ||
1989 | |||
1990 | if (boot_loader_test_memory(pao, dsp_index, dRAM_start_address, | ||
1991 | dRAM_size)) | ||
1992 | return hpi6205_error(dsp_index, HPI6205_ERROR_DSP_EXTMEM); | ||
1993 | return 0; | ||
1994 | } | ||
1995 | |||
1996 | static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index) | ||
1997 | { | ||
1998 | u32 data = 0; | ||
1999 | if (dsp_index == 0) { | ||
2000 | /* only test for DSP0 PLD on ASI5000 card */ | ||
2001 | if (pao->pci.subsys_device_id == 0x5000) { | ||
2002 | /* PLD is located at CE3=0x03000000 */ | ||
2003 | data = boot_loader_read_mem32(pao, dsp_index, | ||
2004 | 0x03000008); | ||
2005 | if ((data & 0xF) != 0x5) | ||
2006 | return hpi6205_error(dsp_index, | ||
2007 | HPI6205_ERROR_DSP_PLD); | ||
2008 | data = boot_loader_read_mem32(pao, dsp_index, | ||
2009 | 0x0300000C); | ||
2010 | if ((data & 0xF) != 0xA) | ||
2011 | return hpi6205_error(dsp_index, | ||
2012 | HPI6205_ERROR_DSP_PLD); | ||
2013 | } | ||
2014 | } else if (dsp_index == 1) { | ||
2015 | /* DSP 1 is a C6713 */ | ||
2016 | if (pao->pci.subsys_device_id == 0x8700) { | ||
2017 | /* PLD is located at CE1=0x90000000 */ | ||
2018 | data = boot_loader_read_mem32(pao, dsp_index, | ||
2019 | 0x90000010); | ||
2020 | if ((data & 0xFF) != 0xAA) | ||
2021 | return hpi6205_error(dsp_index, | ||
2022 | HPI6205_ERROR_DSP_PLD); | ||
2023 | /* 8713 - LED on */ | ||
2024 | boot_loader_write_mem32(pao, dsp_index, 0x90000000, | ||
2025 | 0x02); | ||
2026 | } | ||
2027 | } | ||
2028 | return 0; | ||
2029 | } | ||
2030 | |||
2031 | /** Transfer data to or from DSP | ||
2032 | nOperation = H620_H620_HIF_SEND_DATA or H620_HIF_GET_DATA | ||
2033 | */ | ||
2034 | static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data, | ||
2035 | u32 data_size, int operation) | ||
2036 | { | ||
2037 | struct hpi_hw_obj *phw = pao->priv; | ||
2038 | u32 data_transferred = 0; | ||
2039 | u16 err = 0; | ||
2040 | #ifndef HPI6205_NO_HSR_POLL | ||
2041 | u32 time_out; | ||
2042 | #endif | ||
2043 | u32 temp2; | ||
2044 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
2045 | |||
2046 | if (!p_data) | ||
2047 | return HPI_ERROR_INVALID_DATA_TRANSFER; | ||
2048 | |||
2049 | data_size &= ~3L; /* round data_size down to nearest 4 bytes */ | ||
2050 | |||
2051 | /* make sure state is IDLE */ | ||
2052 | if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) | ||
2053 | return HPI_ERROR_DSP_HARDWARE; | ||
2054 | |||
2055 | while (data_transferred < data_size) { | ||
2056 | u32 this_copy = data_size - data_transferred; | ||
2057 | |||
2058 | if (this_copy > HPI6205_SIZEOF_DATA) | ||
2059 | this_copy = HPI6205_SIZEOF_DATA; | ||
2060 | |||
2061 | if (operation == H620_HIF_SEND_DATA) | ||
2062 | memcpy((void *)&interface->u.b_data[0], | ||
2063 | &p_data[data_transferred], this_copy); | ||
2064 | |||
2065 | interface->transfer_size_in_bytes = this_copy; | ||
2066 | |||
2067 | #ifdef HPI6205_NO_HSR_POLL | ||
2068 | /* DSP must change this back to nOperation */ | ||
2069 | interface->dsp_ack = H620_HIF_IDLE; | ||
2070 | #endif | ||
2071 | |||
2072 | send_dsp_command(phw, operation); | ||
2073 | |||
2074 | #ifdef HPI6205_NO_HSR_POLL | ||
2075 | temp2 = wait_dsp_ack(phw, operation, HPI6205_TIMEOUT); | ||
2076 | HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n", | ||
2077 | HPI6205_TIMEOUT - temp2, this_copy); | ||
2078 | |||
2079 | if (!temp2) { | ||
2080 | /* timed out */ | ||
2081 | HPI_DEBUG_LOG(ERROR, | ||
2082 | "timed out waiting for " "state %d got %d\n", | ||
2083 | operation, interface->dsp_ack); | ||
2084 | |||
2085 | break; | ||
2086 | } | ||
2087 | #else | ||
2088 | /* spin waiting on the result */ | ||
2089 | time_out = HPI6205_TIMEOUT; | ||
2090 | temp2 = 0; | ||
2091 | while ((temp2 == 0) && time_out--) { | ||
2092 | /* give 16k bus mastering transfer time to happen */ | ||
2093 | /*(16k / 132Mbytes/s = 122usec) */ | ||
2094 | hpios_delay_micro_seconds(20); | ||
2095 | temp2 = ioread32(phw->prHSR); | ||
2096 | temp2 &= C6205_HSR_INTSRC; | ||
2097 | } | ||
2098 | HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n", | ||
2099 | HPI6205_TIMEOUT - time_out, this_copy); | ||
2100 | if (temp2 == C6205_HSR_INTSRC) { | ||
2101 | HPI_DEBUG_LOG(VERBOSE, | ||
2102 | "interrupt from HIF <data> OK\n"); | ||
2103 | /* | ||
2104 | if(interface->dwDspAck != nOperation) { | ||
2105 | HPI_DEBUG_LOG(DEBUG("interface->dwDspAck=%d, | ||
2106 | expected %d \n", | ||
2107 | interface->dwDspAck,nOperation); | ||
2108 | } | ||
2109 | */ | ||
2110 | } | ||
2111 | /* need to handle this differently... */ | ||
2112 | else { | ||
2113 | HPI_DEBUG_LOG(ERROR, | ||
2114 | "interrupt from HIF <data> BAD\n"); | ||
2115 | err = HPI_ERROR_DSP_HARDWARE; | ||
2116 | } | ||
2117 | |||
2118 | /* reset the interrupt from the DSP */ | ||
2119 | iowrite32(C6205_HSR_INTSRC, phw->prHSR); | ||
2120 | #endif | ||
2121 | if (operation == H620_HIF_GET_DATA) | ||
2122 | memcpy(&p_data[data_transferred], | ||
2123 | (void *)&interface->u.b_data[0], this_copy); | ||
2124 | |||
2125 | data_transferred += this_copy; | ||
2126 | } | ||
2127 | if (interface->dsp_ack != operation) | ||
2128 | HPI_DEBUG_LOG(DEBUG, "interface->dsp_ack=%d, expected %d\n", | ||
2129 | interface->dsp_ack, operation); | ||
2130 | /* err=HPI_ERROR_DSP_HARDWARE; */ | ||
2131 | |||
2132 | send_dsp_command(phw, H620_HIF_IDLE); | ||
2133 | |||
2134 | return err; | ||
2135 | } | ||
2136 | |||
2137 | /* wait for up to timeout_us microseconds for the DSP | ||
2138 | to signal state by DMA into dwDspAck | ||
2139 | */ | ||
2140 | static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us) | ||
2141 | { | ||
2142 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
2143 | int t = timeout_us / 4; | ||
2144 | |||
2145 | rmb(); /* ensure interface->dsp_ack is up to date */ | ||
2146 | while ((interface->dsp_ack != state) && --t) { | ||
2147 | hpios_delay_micro_seconds(4); | ||
2148 | rmb(); /* DSP changes dsp_ack by DMA */ | ||
2149 | } | ||
2150 | |||
2151 | /*HPI_DEBUG_LOG(VERBOSE, "Spun %d for %d\n", timeout_us/4-t, state); */ | ||
2152 | return t * 4; | ||
2153 | } | ||
2154 | |||
2155 | /* set the busmaster interface to cmd, then interrupt the DSP */ | ||
2156 | static void send_dsp_command(struct hpi_hw_obj *phw, int cmd) | ||
2157 | { | ||
2158 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
2159 | |||
2160 | u32 r; | ||
2161 | |||
2162 | interface->host_cmd = cmd; | ||
2163 | wmb(); /* DSP gets state by DMA, make sure it is written to memory */ | ||
2164 | /* before we interrupt the DSP */ | ||
2165 | r = ioread32(phw->prHDCR); | ||
2166 | r |= (u32)C6205_HDCR_DSPINT; | ||
2167 | iowrite32(r, phw->prHDCR); | ||
2168 | r &= ~(u32)C6205_HDCR_DSPINT; | ||
2169 | iowrite32(r, phw->prHDCR); | ||
2170 | } | ||
2171 | |||
2172 | static unsigned int message_count; | ||
2173 | |||
2174 | static u16 message_response_sequence(struct hpi_adapter_obj *pao, | ||
2175 | struct hpi_message *phm, struct hpi_response *phr) | ||
2176 | { | ||
2177 | #ifndef HPI6205_NO_HSR_POLL | ||
2178 | u32 temp2; | ||
2179 | #endif | ||
2180 | u32 time_out, time_out2; | ||
2181 | struct hpi_hw_obj *phw = pao->priv; | ||
2182 | struct bus_master_interface *interface = phw->p_interface_buffer; | ||
2183 | u16 err = 0; | ||
2184 | |||
2185 | message_count++; | ||
2186 | /* Assume buffer of type struct bus_master_interface | ||
2187 | is allocated "noncacheable" */ | ||
2188 | |||
2189 | if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) { | ||
2190 | HPI_DEBUG_LOG(DEBUG, "timeout waiting for idle\n"); | ||
2191 | return hpi6205_error(0, HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT); | ||
2192 | } | ||
2193 | interface->u.message_buffer = *phm; | ||
2194 | /* signal we want a response */ | ||
2195 | send_dsp_command(phw, H620_HIF_GET_RESP); | ||
2196 | |||
2197 | time_out2 = wait_dsp_ack(phw, H620_HIF_GET_RESP, HPI6205_TIMEOUT); | ||
2198 | |||
2199 | if (time_out2 == 0) { | ||
2200 | HPI_DEBUG_LOG(ERROR, | ||
2201 | "(%u) timed out waiting for " "GET_RESP state [%x]\n", | ||
2202 | message_count, interface->dsp_ack); | ||
2203 | } else { | ||
2204 | HPI_DEBUG_LOG(VERBOSE, | ||
2205 | "(%u) transition to GET_RESP after %u\n", | ||
2206 | message_count, HPI6205_TIMEOUT - time_out2); | ||
2207 | } | ||
2208 | /* spin waiting on HIF interrupt flag (end of msg process) */ | ||
2209 | time_out = HPI6205_TIMEOUT; | ||
2210 | |||
2211 | #ifndef HPI6205_NO_HSR_POLL | ||
2212 | temp2 = 0; | ||
2213 | while ((temp2 == 0) && --time_out) { | ||
2214 | temp2 = ioread32(phw->prHSR); | ||
2215 | temp2 &= C6205_HSR_INTSRC; | ||
2216 | hpios_delay_micro_seconds(1); | ||
2217 | } | ||
2218 | if (temp2 == C6205_HSR_INTSRC) { | ||
2219 | rmb(); /* ensure we see latest value for dsp_ack */ | ||
2220 | if ((interface->dsp_ack != H620_HIF_GET_RESP)) { | ||
2221 | HPI_DEBUG_LOG(DEBUG, | ||
2222 | "(%u)interface->dsp_ack(0x%x) != " | ||
2223 | "H620_HIF_GET_RESP, t=%u\n", message_count, | ||
2224 | interface->dsp_ack, | ||
2225 | HPI6205_TIMEOUT - time_out); | ||
2226 | } else { | ||
2227 | HPI_DEBUG_LOG(VERBOSE, | ||
2228 | "(%u)int with GET_RESP after %u\n", | ||
2229 | message_count, HPI6205_TIMEOUT - time_out); | ||
2230 | } | ||
2231 | |||
2232 | } else { | ||
2233 | /* can we do anything else in response to the error ? */ | ||
2234 | HPI_DEBUG_LOG(ERROR, | ||
2235 | "interrupt from HIF module BAD (function %x)\n", | ||
2236 | phm->function); | ||
2237 | } | ||
2238 | |||
2239 | /* reset the interrupt from the DSP */ | ||
2240 | iowrite32(C6205_HSR_INTSRC, phw->prHSR); | ||
2241 | #endif | ||
2242 | |||
2243 | /* read the result */ | ||
2244 | if (time_out != 0) | ||
2245 | *phr = interface->u.response_buffer; | ||
2246 | |||
2247 | /* set interface back to idle */ | ||
2248 | send_dsp_command(phw, H620_HIF_IDLE); | ||
2249 | |||
2250 | if ((time_out == 0) || (time_out2 == 0)) { | ||
2251 | HPI_DEBUG_LOG(DEBUG, "something timed out!\n"); | ||
2252 | return hpi6205_error(0, HPI6205_ERROR_MSG_RESP_TIMEOUT); | ||
2253 | } | ||
2254 | /* special case for adapter close - */ | ||
2255 | /* wait for the DSP to indicate it is idle */ | ||
2256 | if (phm->function == HPI_ADAPTER_CLOSE) { | ||
2257 | if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) { | ||
2258 | HPI_DEBUG_LOG(DEBUG, | ||
2259 | "timeout waiting for idle " | ||
2260 | "(on adapter_close)\n"); | ||
2261 | return hpi6205_error(0, | ||
2262 | HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT); | ||
2263 | } | ||
2264 | } | ||
2265 | err = hpi_validate_response(phm, phr); | ||
2266 | return err; | ||
2267 | } | ||
2268 | |||
2269 | static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, | ||
2270 | struct hpi_response *phr) | ||
2271 | { | ||
2272 | |||
2273 | u16 err = 0; | ||
2274 | |||
2275 | hpios_dsplock_lock(pao); | ||
2276 | |||
2277 | err = message_response_sequence(pao, phm, phr); | ||
2278 | |||
2279 | /* maybe an error response */ | ||
2280 | if (err) { | ||
2281 | /* something failed in the HPI/DSP interface */ | ||
2282 | phr->error = err; | ||
2283 | pao->dsp_crashed++; | ||
2284 | |||
2285 | /* just the header of the response is valid */ | ||
2286 | phr->size = sizeof(struct hpi_response_header); | ||
2287 | goto err; | ||
2288 | } else | ||
2289 | pao->dsp_crashed = 0; | ||
2290 | |||
2291 | if (phr->error != 0) /* something failed in the DSP */ | ||
2292 | goto err; | ||
2293 | |||
2294 | switch (phm->function) { | ||
2295 | case HPI_OSTREAM_WRITE: | ||
2296 | case HPI_ISTREAM_ANC_WRITE: | ||
2297 | err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data, | ||
2298 | phm->u.d.u.data.data_size, H620_HIF_SEND_DATA); | ||
2299 | break; | ||
2300 | |||
2301 | case HPI_ISTREAM_READ: | ||
2302 | case HPI_OSTREAM_ANC_READ: | ||
2303 | err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data, | ||
2304 | phm->u.d.u.data.data_size, H620_HIF_GET_DATA); | ||
2305 | break; | ||
2306 | |||
2307 | case HPI_CONTROL_SET_STATE: | ||
2308 | if (phm->object == HPI_OBJ_CONTROLEX | ||
2309 | && phm->u.cx.attribute == HPI_COBRANET_SET_DATA) | ||
2310 | err = hpi6205_transfer_data(pao, | ||
2311 | phm->u.cx.u.cobranet_bigdata.pb_data, | ||
2312 | phm->u.cx.u.cobranet_bigdata.byte_count, | ||
2313 | H620_HIF_SEND_DATA); | ||
2314 | break; | ||
2315 | |||
2316 | case HPI_CONTROL_GET_STATE: | ||
2317 | if (phm->object == HPI_OBJ_CONTROLEX | ||
2318 | && phm->u.cx.attribute == HPI_COBRANET_GET_DATA) | ||
2319 | err = hpi6205_transfer_data(pao, | ||
2320 | phm->u.cx.u.cobranet_bigdata.pb_data, | ||
2321 | phr->u.cx.u.cobranet_data.byte_count, | ||
2322 | H620_HIF_GET_DATA); | ||
2323 | break; | ||
2324 | } | ||
2325 | phr->error = err; | ||
2326 | |||
2327 | err: | ||
2328 | hpios_dsplock_unlock(pao); | ||
2329 | |||
2330 | return; | ||
2331 | } | ||
diff --git a/sound/pci/asihpi/hpi6205.h b/sound/pci/asihpi/hpi6205.h new file mode 100644 index 00000000000..1adae0857cd --- /dev/null +++ b/sound/pci/asihpi/hpi6205.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /***************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Host Interface module for an ASI6205 based | ||
20 | bus mastering PCI adapter. | ||
21 | |||
22 | Copyright AudioScience, Inc., 2003 | ||
23 | ******************************************************************************/ | ||
24 | |||
25 | #ifndef _HPI6205_H_ | ||
26 | #define _HPI6205_H_ | ||
27 | |||
28 | /* transitional conditional compile shared between host and DSP */ | ||
29 | /* #define HPI6205_NO_HSR_POLL */ | ||
30 | |||
31 | #include "hpi_internal.h" | ||
32 | |||
33 | /*********************************************************** | ||
34 | Defines used for basic messaging | ||
35 | ************************************************************/ | ||
36 | #define H620_HIF_RESET 0 | ||
37 | #define H620_HIF_IDLE 1 | ||
38 | #define H620_HIF_GET_RESP 2 | ||
39 | #define H620_HIF_DATA_DONE 3 | ||
40 | #define H620_HIF_DATA_MASK 0x10 | ||
41 | #define H620_HIF_SEND_DATA 0x14 | ||
42 | #define H620_HIF_GET_DATA 0x15 | ||
43 | #define H620_HIF_UNKNOWN 0x0000ffff | ||
44 | |||
45 | /*********************************************************** | ||
46 | Types used for mixer control caching | ||
47 | ************************************************************/ | ||
48 | |||
49 | #define H620_MAX_ISTREAMS 32 | ||
50 | #define H620_MAX_OSTREAMS 32 | ||
51 | #define HPI_NMIXER_CONTROLS 2048 | ||
52 | |||
53 | /********************************************************************* | ||
54 | This is used for dynamic control cache allocation | ||
55 | **********************************************************************/ | ||
56 | struct controlcache_6205 { | ||
57 | u32 number_of_controls; | ||
58 | u32 physical_address32; | ||
59 | u32 size_in_bytes; | ||
60 | }; | ||
61 | |||
62 | /********************************************************************* | ||
63 | This is used for dynamic allocation of async event array | ||
64 | **********************************************************************/ | ||
65 | struct async_event_buffer_6205 { | ||
66 | u32 physical_address32; | ||
67 | u32 spare; | ||
68 | struct hpi_fifo_buffer b; | ||
69 | }; | ||
70 | |||
71 | /*********************************************************** | ||
72 | The Host located memory buffer that the 6205 will bus master | ||
73 | in and out of. | ||
74 | ************************************************************/ | ||
75 | #define HPI6205_SIZEOF_DATA (16*1024) | ||
76 | struct bus_master_interface { | ||
77 | u32 host_cmd; | ||
78 | u32 dsp_ack; | ||
79 | u32 transfer_size_in_bytes; | ||
80 | union { | ||
81 | struct hpi_message message_buffer; | ||
82 | struct hpi_response response_buffer; | ||
83 | u8 b_data[HPI6205_SIZEOF_DATA]; | ||
84 | } u; | ||
85 | struct controlcache_6205 control_cache; | ||
86 | struct async_event_buffer_6205 async_buffer; | ||
87 | struct hpi_hostbuffer_status | ||
88 | instream_host_buffer_status[H620_MAX_ISTREAMS]; | ||
89 | struct hpi_hostbuffer_status | ||
90 | outstream_host_buffer_status[H620_MAX_OSTREAMS]; | ||
91 | }; | ||
92 | |||
93 | #endif | ||
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h new file mode 100644 index 00000000000..f1cd6f1a0d4 --- /dev/null +++ b/sound/pci/asihpi/hpi_internal.h | |||
@@ -0,0 +1,1641 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | HPI internal definitions | ||
20 | |||
21 | (C) Copyright AudioScience Inc. 1996-2009 | ||
22 | ******************************************************************************/ | ||
23 | |||
24 | #ifndef _HPI_INTERNAL_H_ | ||
25 | #define _HPI_INTERNAL_H_ | ||
26 | |||
27 | #include "hpi.h" | ||
28 | /** maximum number of memory regions mapped to an adapter */ | ||
29 | #define HPI_MAX_ADAPTER_MEM_SPACES (2) | ||
30 | |||
31 | /* Each OS needs its own hpios.h, or specific define as above */ | ||
32 | #include "hpios.h" | ||
33 | |||
34 | /* physical memory allocation */ | ||
35 | void hpios_locked_mem_init(void | ||
36 | ); | ||
37 | void hpios_locked_mem_free_all(void | ||
38 | ); | ||
39 | #define hpios_locked_mem_prepare(a, b, c, d); | ||
40 | #define hpios_locked_mem_unprepare(a) | ||
41 | |||
42 | /** Allocate and map an area of locked memory for bus master DMA operations. | ||
43 | |||
44 | On success, *pLockedMemeHandle is a valid handle, and 0 is returned | ||
45 | On error *pLockedMemHandle marked invalid, non-zero returned. | ||
46 | |||
47 | If this function succeeds, then HpiOs_LockedMem_GetVirtAddr() and | ||
48 | HpiOs_LockedMem_GetPyhsAddr() will always succed on the returned handle. | ||
49 | */ | ||
50 | u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_locked_mem_handle, | ||
51 | /**< memory handle */ | ||
52 | u32 size, /**< size in bytes to allocate */ | ||
53 | struct pci_dev *p_os_reference | ||
54 | /**< OS specific data required for memory allocation */ | ||
55 | ); | ||
56 | |||
57 | /** Free mapping and memory represented by LockedMemHandle | ||
58 | |||
59 | Frees any resources, then invalidates the handle. | ||
60 | Returns 0 on success, 1 if handle is invalid. | ||
61 | |||
62 | */ | ||
63 | u16 hpios_locked_mem_free(struct consistent_dma_area *locked_mem_handle); | ||
64 | |||
65 | /** Get the physical PCI address of memory represented by LockedMemHandle. | ||
66 | |||
67 | If handle is invalid *pPhysicalAddr is set to zero and return 1 | ||
68 | */ | ||
69 | u16 hpios_locked_mem_get_phys_addr(struct consistent_dma_area | ||
70 | *locked_mem_handle, u32 *p_physical_addr); | ||
71 | |||
72 | /** Get the CPU address of of memory represented by LockedMemHandle. | ||
73 | |||
74 | If handle is NULL *ppvVirtualAddr is set to NULL and return 1 | ||
75 | */ | ||
76 | u16 hpios_locked_mem_get_virt_addr(struct consistent_dma_area | ||
77 | *locked_mem_handle, void **ppv_virtual_addr); | ||
78 | |||
79 | /** Check that handle is valid | ||
80 | i.e it represents a valid memory area | ||
81 | */ | ||
82 | u16 hpios_locked_mem_valid(struct consistent_dma_area *locked_mem_handle); | ||
83 | |||
84 | /* timing/delay */ | ||
85 | void hpios_delay_micro_seconds(u32 num_micro_sec); | ||
86 | |||
87 | struct hpi_message; | ||
88 | struct hpi_response; | ||
89 | |||
90 | typedef void hpi_handler_func(struct hpi_message *, struct hpi_response *); | ||
91 | |||
92 | /* If the assert fails, compiler complains | ||
93 | something like size of array `msg' is negative. | ||
94 | Unlike linux BUILD_BUG_ON, this works outside function scope. | ||
95 | */ | ||
96 | #define compile_time_assert(cond, msg) \ | ||
97 | typedef char ASSERT_##msg[(cond) ? 1 : -1] | ||
98 | |||
99 | /*/////////////////////////////////////////////////////////////////////////// */ | ||
100 | /* Private HPI Entity related definitions */ | ||
101 | |||
102 | #define STR_SIZE_FIELD_MAX 65535U | ||
103 | #define STR_TYPE_FIELD_MAX 255U | ||
104 | #define STR_ROLE_FIELD_MAX 255U | ||
105 | |||
106 | struct hpi_entity_str { | ||
107 | uint16_t size; | ||
108 | uint8_t type; | ||
109 | uint8_t role; | ||
110 | }; | ||
111 | |||
112 | #if defined(_MSC_VER) | ||
113 | #pragma warning(push) | ||
114 | #pragma warning(disable : 4200) | ||
115 | #endif | ||
116 | |||
117 | struct hpi_entity { | ||
118 | struct hpi_entity_str header; | ||
119 | #if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008)) | ||
120 | /* DSP C6000 compiler v6.0.8 and lower | ||
121 | do not support flexible array member */ | ||
122 | uint8_t value[]; | ||
123 | #else | ||
124 | /* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */ | ||
125 | #define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE | ||
126 | uint8_t value[1]; | ||
127 | #endif | ||
128 | }; | ||
129 | |||
130 | #if defined(_MSC_VER) | ||
131 | #pragma warning(pop) | ||
132 | #endif | ||
133 | |||
134 | /******************************************* bus types */ | ||
135 | enum HPI_BUSES { | ||
136 | HPI_BUS_ISAPNP = 1, | ||
137 | HPI_BUS_PCI = 2, | ||
138 | HPI_BUS_USB = 3, | ||
139 | HPI_BUS_NET = 4 | ||
140 | }; | ||
141 | |||
142 | /******************************************* CONTROL ATTRIBUTES ****/ | ||
143 | /* (in order of control type ID */ | ||
144 | |||
145 | /* This allows for 255 control types, 256 unique attributes each */ | ||
146 | #define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai) | ||
147 | |||
148 | /* Get the sub-index of the attribute for a control type */ | ||
149 | #define HPI_CTL_ATTR_INDEX(i) (i&0xff) | ||
150 | |||
151 | /* Generic control attributes. */ | ||
152 | |||
153 | /** Enable a control. | ||
154 | 0=disable, 1=enable | ||
155 | \note generic to all mixer plugins? | ||
156 | */ | ||
157 | #define HPI_GENERIC_ENABLE HPI_CTL_ATTR(GENERIC, 1) | ||
158 | |||
159 | /** Enable event generation for a control. | ||
160 | 0=disable, 1=enable | ||
161 | \note generic to all controls that can generate events | ||
162 | */ | ||
163 | #define HPI_GENERIC_EVENT_ENABLE HPI_CTL_ATTR(GENERIC, 2) | ||
164 | |||
165 | /* Volume Control attributes */ | ||
166 | #define HPI_VOLUME_GAIN HPI_CTL_ATTR(VOLUME, 1) | ||
167 | #define HPI_VOLUME_AUTOFADE HPI_CTL_ATTR(VOLUME, 2) | ||
168 | |||
169 | /** For HPI_ControlQuery() to get the number of channels of a volume control*/ | ||
170 | #define HPI_VOLUME_NUM_CHANNELS HPI_CTL_ATTR(VOLUME, 6) | ||
171 | #define HPI_VOLUME_RANGE HPI_CTL_ATTR(VOLUME, 10) | ||
172 | |||
173 | /** Level Control attributes */ | ||
174 | #define HPI_LEVEL_GAIN HPI_CTL_ATTR(LEVEL, 1) | ||
175 | #define HPI_LEVEL_RANGE HPI_CTL_ATTR(LEVEL, 10) | ||
176 | |||
177 | /* Meter Control attributes */ | ||
178 | /** return RMS signal level */ | ||
179 | #define HPI_METER_RMS HPI_CTL_ATTR(METER, 1) | ||
180 | /** return peak signal level */ | ||
181 | #define HPI_METER_PEAK HPI_CTL_ATTR(METER, 2) | ||
182 | /** ballistics for ALL rms meters on adapter */ | ||
183 | #define HPI_METER_RMS_BALLISTICS HPI_CTL_ATTR(METER, 3) | ||
184 | /** ballistics for ALL peak meters on adapter */ | ||
185 | #define HPI_METER_PEAK_BALLISTICS HPI_CTL_ATTR(METER, 4) | ||
186 | |||
187 | /** For HPI_ControlQuery() to get the number of channels of a meter control*/ | ||
188 | #define HPI_METER_NUM_CHANNELS HPI_CTL_ATTR(METER, 5) | ||
189 | |||
190 | /* Multiplexer control attributes */ | ||
191 | #define HPI_MULTIPLEXER_SOURCE HPI_CTL_ATTR(MULTIPLEXER, 1) | ||
192 | #define HPI_MULTIPLEXER_QUERYSOURCE HPI_CTL_ATTR(MULTIPLEXER, 2) | ||
193 | |||
194 | /** AES/EBU transmitter control attributes */ | ||
195 | /** AESEBU or SPDIF */ | ||
196 | #define HPI_AESEBUTX_FORMAT HPI_CTL_ATTR(AESEBUTX, 1) | ||
197 | #define HPI_AESEBUTX_SAMPLERATE HPI_CTL_ATTR(AESEBUTX, 3) | ||
198 | #define HPI_AESEBUTX_CHANNELSTATUS HPI_CTL_ATTR(AESEBUTX, 4) | ||
199 | #define HPI_AESEBUTX_USERDATA HPI_CTL_ATTR(AESEBUTX, 5) | ||
200 | |||
201 | /** AES/EBU receiver control attributes */ | ||
202 | #define HPI_AESEBURX_FORMAT HPI_CTL_ATTR(AESEBURX, 1) | ||
203 | #define HPI_AESEBURX_ERRORSTATUS HPI_CTL_ATTR(AESEBURX, 2) | ||
204 | #define HPI_AESEBURX_SAMPLERATE HPI_CTL_ATTR(AESEBURX, 3) | ||
205 | #define HPI_AESEBURX_CHANNELSTATUS HPI_CTL_ATTR(AESEBURX, 4) | ||
206 | #define HPI_AESEBURX_USERDATA HPI_CTL_ATTR(AESEBURX, 5) | ||
207 | |||
208 | /** \defgroup tuner_defs Tuners | ||
209 | \{ | ||
210 | */ | ||
211 | /** \defgroup tuner_attrs Tuner control attributes | ||
212 | \{ | ||
213 | */ | ||
214 | #define HPI_TUNER_BAND HPI_CTL_ATTR(TUNER, 1) | ||
215 | #define HPI_TUNER_FREQ HPI_CTL_ATTR(TUNER, 2) | ||
216 | #define HPI_TUNER_LEVEL HPI_CTL_ATTR(TUNER, 3) | ||
217 | #define HPI_TUNER_AUDIOMUTE HPI_CTL_ATTR(TUNER, 4) | ||
218 | /* use TUNER_STATUS instead */ | ||
219 | #define HPI_TUNER_VIDEO_STATUS HPI_CTL_ATTR(TUNER, 5) | ||
220 | #define HPI_TUNER_GAIN HPI_CTL_ATTR(TUNER, 6) | ||
221 | #define HPI_TUNER_STATUS HPI_CTL_ATTR(TUNER, 7) | ||
222 | #define HPI_TUNER_MODE HPI_CTL_ATTR(TUNER, 8) | ||
223 | /** RDS data. */ | ||
224 | #define HPI_TUNER_RDS HPI_CTL_ATTR(TUNER, 9) | ||
225 | /** Audio pre-emphasis. */ | ||
226 | #define HPI_TUNER_DEEMPHASIS HPI_CTL_ATTR(TUNER, 10) | ||
227 | /** HD Radio tuner program control. */ | ||
228 | #define HPI_TUNER_PROGRAM HPI_CTL_ATTR(TUNER, 11) | ||
229 | /** HD Radio tuner digital signal quality. */ | ||
230 | #define HPI_TUNER_HDRADIO_SIGNAL_QUALITY HPI_CTL_ATTR(TUNER, 12) | ||
231 | /** HD Radio SDK firmware version. */ | ||
232 | #define HPI_TUNER_HDRADIO_SDK_VERSION HPI_CTL_ATTR(TUNER, 13) | ||
233 | /** HD Radio DSP firmware version. */ | ||
234 | #define HPI_TUNER_HDRADIO_DSP_VERSION HPI_CTL_ATTR(TUNER, 14) | ||
235 | |||
236 | /** \} */ | ||
237 | |||
238 | /** \defgroup pads_attrs Tuner PADs control attributes | ||
239 | \{ | ||
240 | */ | ||
241 | /** The text string containing the station/channel combination. */ | ||
242 | #define HPI_PAD_CHANNEL_NAME HPI_CTL_ATTR(PAD, 1) | ||
243 | /** The text string containing the artist. */ | ||
244 | #define HPI_PAD_ARTIST HPI_CTL_ATTR(PAD, 2) | ||
245 | /** The text string containing the title. */ | ||
246 | #define HPI_PAD_TITLE HPI_CTL_ATTR(PAD, 3) | ||
247 | /** The text string containing the comment. */ | ||
248 | #define HPI_PAD_COMMENT HPI_CTL_ATTR(PAD, 4) | ||
249 | /** The integer containing the PTY code. */ | ||
250 | #define HPI_PAD_PROGRAM_TYPE HPI_CTL_ATTR(PAD, 5) | ||
251 | /** The integer containing the program identification. */ | ||
252 | #define HPI_PAD_PROGRAM_ID HPI_CTL_ATTR(PAD, 6) | ||
253 | /** The integer containing whether traffic information is supported. | ||
254 | Contains either 1 or 0. */ | ||
255 | #define HPI_PAD_TA_SUPPORT HPI_CTL_ATTR(PAD, 7) | ||
256 | /** The integer containing whether traffic announcement is in progress. | ||
257 | Contains either 1 or 0. */ | ||
258 | #define HPI_PAD_TA_ACTIVE HPI_CTL_ATTR(PAD, 8) | ||
259 | /** \} */ | ||
260 | /** \} */ | ||
261 | |||
262 | /* VOX control attributes */ | ||
263 | #define HPI_VOX_THRESHOLD HPI_CTL_ATTR(VOX, 1) | ||
264 | |||
265 | /*?? channel mode used hpi_multiplexer_source attribute == 1 */ | ||
266 | #define HPI_CHANNEL_MODE_MODE HPI_CTL_ATTR(CHANNEL_MODE, 1) | ||
267 | |||
268 | /** \defgroup channel_modes Channel Modes | ||
269 | Used for HPI_ChannelModeSet/Get() | ||
270 | \{ | ||
271 | */ | ||
272 | /** Left channel out = left channel in, Right channel out = right channel in. */ | ||
273 | #define HPI_CHANNEL_MODE_NORMAL 1 | ||
274 | /** Left channel out = right channel in, Right channel out = left channel in. */ | ||
275 | #define HPI_CHANNEL_MODE_SWAP 2 | ||
276 | /** Left channel out = left channel in, Right channel out = left channel in. */ | ||
277 | #define HPI_CHANNEL_MODE_LEFT_TO_STEREO 3 | ||
278 | /** Left channel out = right channel in, Right channel out = right channel in.*/ | ||
279 | #define HPI_CHANNEL_MODE_RIGHT_TO_STEREO 4 | ||
280 | /** Left channel out = (left channel in + right channel in)/2, | ||
281 | Right channel out = mute. */ | ||
282 | #define HPI_CHANNEL_MODE_STEREO_TO_LEFT 5 | ||
283 | /** Left channel out = mute, | ||
284 | Right channel out = (right channel in + left channel in)/2. */ | ||
285 | #define HPI_CHANNEL_MODE_STEREO_TO_RIGHT 6 | ||
286 | #define HPI_CHANNEL_MODE_LAST 6 | ||
287 | /** \} */ | ||
288 | |||
289 | /* Bitstream control set attributes */ | ||
290 | #define HPI_BITSTREAM_DATA_POLARITY HPI_CTL_ATTR(BITSTREAM, 1) | ||
291 | #define HPI_BITSTREAM_CLOCK_EDGE HPI_CTL_ATTR(BITSTREAM, 2) | ||
292 | #define HPI_BITSTREAM_CLOCK_SOURCE HPI_CTL_ATTR(BITSTREAM, 3) | ||
293 | |||
294 | #define HPI_POLARITY_POSITIVE 0 | ||
295 | #define HPI_POLARITY_NEGATIVE 1 | ||
296 | |||
297 | /* Bitstream control get attributes */ | ||
298 | #define HPI_BITSTREAM_ACTIVITY 1 | ||
299 | |||
300 | /* SampleClock control attributes */ | ||
301 | #define HPI_SAMPLECLOCK_SOURCE HPI_CTL_ATTR(SAMPLECLOCK, 1) | ||
302 | #define HPI_SAMPLECLOCK_SAMPLERATE HPI_CTL_ATTR(SAMPLECLOCK, 2) | ||
303 | #define HPI_SAMPLECLOCK_SOURCE_INDEX HPI_CTL_ATTR(SAMPLECLOCK, 3) | ||
304 | #define HPI_SAMPLECLOCK_LOCAL_SAMPLERATE\ | ||
305 | HPI_CTL_ATTR(SAMPLECLOCK, 4) | ||
306 | #define HPI_SAMPLECLOCK_AUTO HPI_CTL_ATTR(SAMPLECLOCK, 5) | ||
307 | #define HPI_SAMPLECLOCK_LOCAL_LOCK HPI_CTL_ATTR(SAMPLECLOCK, 6) | ||
308 | |||
309 | /* Microphone control attributes */ | ||
310 | #define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1) | ||
311 | |||
312 | /** Equalizer control attributes | ||
313 | */ | ||
314 | /** Used to get number of filters in an EQ. (Can't set) */ | ||
315 | #define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1) | ||
316 | /** Set/get the filter by type, freq, Q, gain */ | ||
317 | #define HPI_EQUALIZER_FILTER HPI_CTL_ATTR(EQUALIZER, 2) | ||
318 | /** Get the biquad coefficients */ | ||
319 | #define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3) | ||
320 | |||
321 | #define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1) | ||
322 | |||
323 | /* Cobranet control attributes. | ||
324 | MUST be distinct from all other control attributes. | ||
325 | This is so that host side processing can easily identify a Cobranet control | ||
326 | and apply additional host side operations (like copying data) as required. | ||
327 | */ | ||
328 | #define HPI_COBRANET_SET HPI_CTL_ATTR(COBRANET, 1) | ||
329 | #define HPI_COBRANET_GET HPI_CTL_ATTR(COBRANET, 2) | ||
330 | #define HPI_COBRANET_SET_DATA HPI_CTL_ATTR(COBRANET, 3) | ||
331 | #define HPI_COBRANET_GET_DATA HPI_CTL_ATTR(COBRANET, 4) | ||
332 | #define HPI_COBRANET_GET_STATUS HPI_CTL_ATTR(COBRANET, 5) | ||
333 | #define HPI_COBRANET_SEND_PACKET HPI_CTL_ATTR(COBRANET, 6) | ||
334 | #define HPI_COBRANET_GET_PACKET HPI_CTL_ATTR(COBRANET, 7) | ||
335 | |||
336 | /*------------------------------------------------------------ | ||
337 | Cobranet Chip Bridge - copied from HMI.H | ||
338 | ------------------------------------------------------------*/ | ||
339 | #define HPI_COBRANET_HMI_cobra_bridge 0x20000 | ||
340 | #define HPI_COBRANET_HMI_cobra_bridge_tx_pkt_buf \ | ||
341 | (HPI_COBRANET_HMI_cobra_bridge + 0x1000) | ||
342 | #define HPI_COBRANET_HMI_cobra_bridge_rx_pkt_buf \ | ||
343 | (HPI_COBRANET_HMI_cobra_bridge + 0x2000) | ||
344 | #define HPI_COBRANET_HMI_cobra_if_table1 0x110000 | ||
345 | #define HPI_COBRANET_HMI_cobra_if_phy_address \ | ||
346 | (HPI_COBRANET_HMI_cobra_if_table1 + 0xd) | ||
347 | #define HPI_COBRANET_HMI_cobra_protocolIP 0x72000 | ||
348 | #define HPI_COBRANET_HMI_cobra_ip_mon_currentIP \ | ||
349 | (HPI_COBRANET_HMI_cobra_protocolIP + 0x0) | ||
350 | #define HPI_COBRANET_HMI_cobra_ip_mon_staticIP \ | ||
351 | (HPI_COBRANET_HMI_cobra_protocolIP + 0x2) | ||
352 | #define HPI_COBRANET_HMI_cobra_sys 0x100000 | ||
353 | #define HPI_COBRANET_HMI_cobra_sys_desc \ | ||
354 | (HPI_COBRANET_HMI_cobra_sys + 0x0) | ||
355 | #define HPI_COBRANET_HMI_cobra_sys_objectID \ | ||
356 | (HPI_COBRANET_HMI_cobra_sys + 0x100) | ||
357 | #define HPI_COBRANET_HMI_cobra_sys_contact \ | ||
358 | (HPI_COBRANET_HMI_cobra_sys + 0x200) | ||
359 | #define HPI_COBRANET_HMI_cobra_sys_name \ | ||
360 | (HPI_COBRANET_HMI_cobra_sys + 0x300) | ||
361 | #define HPI_COBRANET_HMI_cobra_sys_location \ | ||
362 | (HPI_COBRANET_HMI_cobra_sys + 0x400) | ||
363 | |||
364 | /*------------------------------------------------------------ | ||
365 | Cobranet Chip Status bits | ||
366 | ------------------------------------------------------------*/ | ||
367 | #define HPI_COBRANET_HMI_STATUS_RXPACKET 2 | ||
368 | #define HPI_COBRANET_HMI_STATUS_TXPACKET 3 | ||
369 | |||
370 | /*------------------------------------------------------------ | ||
371 | Ethernet header size | ||
372 | ------------------------------------------------------------*/ | ||
373 | #define HPI_ETHERNET_HEADER_SIZE (16) | ||
374 | |||
375 | /* These defines are used to fill in protocol information for an Ethernet packet | ||
376 | sent using HMI on CS18102 */ | ||
377 | /** ID supplied by Cirrius for ASI packets. */ | ||
378 | #define HPI_ETHERNET_PACKET_ID 0x85 | ||
379 | /** Simple packet - no special routing required */ | ||
380 | #define HPI_ETHERNET_PACKET_V1 0x01 | ||
381 | /** This packet must make its way to the host across the HPI interface */ | ||
382 | #define HPI_ETHERNET_PACKET_HOSTED_VIA_HMI 0x20 | ||
383 | /** This packet must make its way to the host across the HPI interface */ | ||
384 | #define HPI_ETHERNET_PACKET_HOSTED_VIA_HMI_V1 0x21 | ||
385 | /** This packet must make its way to the host across the HPI interface */ | ||
386 | #define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI 0x40 | ||
387 | /** This packet must make its way to the host across the HPI interface */ | ||
388 | #define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1 0x41 | ||
389 | |||
390 | #define HPI_ETHERNET_UDP_PORT (44600) /*!< UDP messaging port */ | ||
391 | |||
392 | /** Base network time out is set to 100 milli-seconds. */ | ||
393 | #define HPI_ETHERNET_TIMEOUT_MS (100) | ||
394 | |||
395 | /** \defgroup tonedet_attr Tonedetector attributes | ||
396 | \{ | ||
397 | Used by HPI_ToneDetector_Set() and HPI_ToneDetector_Get() | ||
398 | */ | ||
399 | |||
400 | /** Set the threshold level of a tonedetector, | ||
401 | Threshold is a -ve number in units of dB/100, | ||
402 | */ | ||
403 | #define HPI_TONEDETECTOR_THRESHOLD HPI_CTL_ATTR(TONEDETECTOR, 1) | ||
404 | |||
405 | /** Get the current state of tonedetection | ||
406 | The result is a bitmap of detected tones. pairs of bits represent the left | ||
407 | and right channels, with left channel in LSB. | ||
408 | The lowest frequency detector state is in the LSB | ||
409 | */ | ||
410 | #define HPI_TONEDETECTOR_STATE HPI_CTL_ATTR(TONEDETECTOR, 2) | ||
411 | |||
412 | /** Get the frequency of a tonedetector band. | ||
413 | */ | ||
414 | #define HPI_TONEDETECTOR_FREQUENCY HPI_CTL_ATTR(TONEDETECTOR, 3) | ||
415 | |||
416 | /**\}*/ | ||
417 | |||
418 | /** \defgroup silencedet_attr SilenceDetector attributes | ||
419 | \{ | ||
420 | */ | ||
421 | |||
422 | /** Get the current state of tonedetection | ||
423 | The result is a bitmap with 1s for silent channels. Left channel is in LSB | ||
424 | */ | ||
425 | #define HPI_SILENCEDETECTOR_STATE \ | ||
426 | HPI_CTL_ATTR(SILENCEDETECTOR, 2) | ||
427 | |||
428 | /** Set the threshold level of a SilenceDetector, | ||
429 | Threshold is a -ve number in units of dB/100, | ||
430 | */ | ||
431 | #define HPI_SILENCEDETECTOR_THRESHOLD \ | ||
432 | HPI_CTL_ATTR(SILENCEDETECTOR, 1) | ||
433 | |||
434 | /** get/set the silence time before the detector triggers | ||
435 | */ | ||
436 | #define HPI_SILENCEDETECTOR_DELAY \ | ||
437 | HPI_CTL_ATTR(SILENCEDETECTOR, 3) | ||
438 | |||
439 | /**\}*/ | ||
440 | |||
441 | /* Locked memory buffer alloc/free phases */ | ||
442 | /** use one message to allocate or free physical memory */ | ||
443 | #define HPI_BUFFER_CMD_EXTERNAL 0 | ||
444 | /** alloc physical memory */ | ||
445 | #define HPI_BUFFER_CMD_INTERNAL_ALLOC 1 | ||
446 | /** send physical memory address to adapter */ | ||
447 | #define HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER 2 | ||
448 | /** notify adapter to stop using physical buffer */ | ||
449 | #define HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER 3 | ||
450 | /** free physical buffer */ | ||
451 | #define HPI_BUFFER_CMD_INTERNAL_FREE 4 | ||
452 | |||
453 | /******************************************* CONTROLX ATTRIBUTES ****/ | ||
454 | /* NOTE: All controlx attributes must be unique, unlike control attributes */ | ||
455 | |||
456 | /*****************************************************************************/ | ||
457 | /*****************************************************************************/ | ||
458 | /******** HPI LOW LEVEL MESSAGES *******/ | ||
459 | /*****************************************************************************/ | ||
460 | /*****************************************************************************/ | ||
461 | /** Pnp ids */ | ||
462 | /** "ASI" - actual is "ASX" - need to change */ | ||
463 | #define HPI_ID_ISAPNP_AUDIOSCIENCE 0x0669 | ||
464 | /** PCI vendor ID that AudioScience uses */ | ||
465 | #define HPI_PCI_VENDOR_ID_AUDIOSCIENCE 0x175C | ||
466 | /** PCI vendor ID that the DSP56301 has */ | ||
467 | #define HPI_PCI_VENDOR_ID_MOTOROLA 0x1057 | ||
468 | /** PCI vendor ID that TI uses */ | ||
469 | #define HPI_PCI_VENDOR_ID_TI 0x104C | ||
470 | |||
471 | #define HPI_PCI_DEV_ID_PCI2040 0xAC60 | ||
472 | /** TI's C6205 PCI interface has this ID */ | ||
473 | #define HPI_PCI_DEV_ID_DSP6205 0xA106 | ||
474 | |||
475 | #define HPI_USB_VENDOR_ID_AUDIOSCIENCE 0x1257 | ||
476 | #define HPI_USB_W2K_TAG 0x57495341 /* "ASIW" */ | ||
477 | #define HPI_USB_LINUX_TAG 0x4C495341 /* "ASIL" */ | ||
478 | |||
479 | /** First 2 hex digits define the adapter family */ | ||
480 | #define HPI_ADAPTER_FAMILY_MASK 0xff00 | ||
481 | |||
482 | #define HPI_ADAPTER_FAMILY_ASI(f) (f & HPI_ADAPTER_FAMILY_MASK) | ||
483 | #define HPI_ADAPTER_ASI(f) (f) | ||
484 | |||
485 | /******************************************* message types */ | ||
486 | #define HPI_TYPE_MESSAGE 1 | ||
487 | #define HPI_TYPE_RESPONSE 2 | ||
488 | #define HPI_TYPE_DATA 3 | ||
489 | #define HPI_TYPE_SSX2BYPASS_MESSAGE 4 | ||
490 | |||
491 | /******************************************* object types */ | ||
492 | #define HPI_OBJ_SUBSYSTEM 1 | ||
493 | #define HPI_OBJ_ADAPTER 2 | ||
494 | #define HPI_OBJ_OSTREAM 3 | ||
495 | #define HPI_OBJ_ISTREAM 4 | ||
496 | #define HPI_OBJ_MIXER 5 | ||
497 | #define HPI_OBJ_NODE 6 | ||
498 | #define HPI_OBJ_CONTROL 7 | ||
499 | #define HPI_OBJ_NVMEMORY 8 | ||
500 | #define HPI_OBJ_GPIO 9 | ||
501 | #define HPI_OBJ_WATCHDOG 10 | ||
502 | #define HPI_OBJ_CLOCK 11 | ||
503 | #define HPI_OBJ_PROFILE 12 | ||
504 | #define HPI_OBJ_CONTROLEX 13 | ||
505 | #define HPI_OBJ_ASYNCEVENT 14 | ||
506 | |||
507 | #define HPI_OBJ_MAXINDEX 14 | ||
508 | |||
509 | /******************************************* methods/functions */ | ||
510 | |||
511 | #define HPI_OBJ_FUNCTION_SPACING 0x100 | ||
512 | #define HPI_MAKE_INDEX(obj, index) (obj * HPI_OBJ_FUNCTION_SPACING + index) | ||
513 | #define HPI_EXTRACT_INDEX(fn) (fn & 0xff) | ||
514 | |||
515 | /* SUB-SYSTEM */ | ||
516 | #define HPI_SUBSYS_OPEN HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 1) | ||
517 | #define HPI_SUBSYS_GET_VERSION HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 2) | ||
518 | #define HPI_SUBSYS_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 3) | ||
519 | #define HPI_SUBSYS_FIND_ADAPTERS HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 4) | ||
520 | #define HPI_SUBSYS_CREATE_ADAPTER HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 5) | ||
521 | #define HPI_SUBSYS_CLOSE HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 6) | ||
522 | #define HPI_SUBSYS_DELETE_ADAPTER HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 7) | ||
523 | #define HPI_SUBSYS_DRIVER_LOAD HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 8) | ||
524 | #define HPI_SUBSYS_DRIVER_UNLOAD HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 9) | ||
525 | #define HPI_SUBSYS_READ_PORT_8 HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 10) | ||
526 | #define HPI_SUBSYS_WRITE_PORT_8 HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 11) | ||
527 | #define HPI_SUBSYS_GET_NUM_ADAPTERS HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 12) | ||
528 | #define HPI_SUBSYS_GET_ADAPTER HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 13) | ||
529 | #define HPI_SUBSYS_SET_NETWORK_INTERFACE HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 14) | ||
530 | #define HPI_SUBSYS_FUNCTION_COUNT 14 | ||
531 | /* ADAPTER */ | ||
532 | #define HPI_ADAPTER_OPEN HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 1) | ||
533 | #define HPI_ADAPTER_CLOSE HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 2) | ||
534 | #define HPI_ADAPTER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 3) | ||
535 | #define HPI_ADAPTER_GET_ASSERT HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 4) | ||
536 | #define HPI_ADAPTER_TEST_ASSERT HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 5) | ||
537 | #define HPI_ADAPTER_SET_MODE HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 6) | ||
538 | #define HPI_ADAPTER_GET_MODE HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 7) | ||
539 | #define HPI_ADAPTER_ENABLE_CAPABILITY HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 8) | ||
540 | #define HPI_ADAPTER_SELFTEST HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 9) | ||
541 | #define HPI_ADAPTER_FIND_OBJECT HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 10) | ||
542 | #define HPI_ADAPTER_QUERY_FLASH HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 11) | ||
543 | #define HPI_ADAPTER_START_FLASH HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 12) | ||
544 | #define HPI_ADAPTER_PROGRAM_FLASH HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 13) | ||
545 | #define HPI_ADAPTER_SET_PROPERTY HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 14) | ||
546 | #define HPI_ADAPTER_GET_PROPERTY HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 15) | ||
547 | #define HPI_ADAPTER_ENUM_PROPERTY HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 16) | ||
548 | #define HPI_ADAPTER_MODULE_INFO HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 17) | ||
549 | #define HPI_ADAPTER_DEBUG_READ HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 18) | ||
550 | #define HPI_ADAPTER_FUNCTION_COUNT 18 | ||
551 | /* OUTPUT STREAM */ | ||
552 | #define HPI_OSTREAM_OPEN HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 1) | ||
553 | #define HPI_OSTREAM_CLOSE HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 2) | ||
554 | #define HPI_OSTREAM_WRITE HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 3) | ||
555 | #define HPI_OSTREAM_START HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 4) | ||
556 | #define HPI_OSTREAM_STOP HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 5) | ||
557 | #define HPI_OSTREAM_RESET HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 6) | ||
558 | #define HPI_OSTREAM_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 7) | ||
559 | #define HPI_OSTREAM_QUERY_FORMAT HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 8) | ||
560 | #define HPI_OSTREAM_DATA HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 9) | ||
561 | #define HPI_OSTREAM_SET_VELOCITY HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 10) | ||
562 | #define HPI_OSTREAM_SET_PUNCHINOUT HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 11) | ||
563 | #define HPI_OSTREAM_SINEGEN HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 12) | ||
564 | #define HPI_OSTREAM_ANC_RESET HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 13) | ||
565 | #define HPI_OSTREAM_ANC_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 14) | ||
566 | #define HPI_OSTREAM_ANC_READ HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 15) | ||
567 | #define HPI_OSTREAM_SET_TIMESCALE HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 16) | ||
568 | #define HPI_OSTREAM_SET_FORMAT HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 17) | ||
569 | #define HPI_OSTREAM_HOSTBUFFER_ALLOC HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 18) | ||
570 | #define HPI_OSTREAM_HOSTBUFFER_FREE HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 19) | ||
571 | #define HPI_OSTREAM_GROUP_ADD HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 20) | ||
572 | #define HPI_OSTREAM_GROUP_GETMAP HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 21) | ||
573 | #define HPI_OSTREAM_GROUP_RESET HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 22) | ||
574 | #define HPI_OSTREAM_HOSTBUFFER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 23) | ||
575 | #define HPI_OSTREAM_WAIT_START HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 24) | ||
576 | #define HPI_OSTREAM_FUNCTION_COUNT 24 | ||
577 | /* INPUT STREAM */ | ||
578 | #define HPI_ISTREAM_OPEN HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 1) | ||
579 | #define HPI_ISTREAM_CLOSE HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 2) | ||
580 | #define HPI_ISTREAM_SET_FORMAT HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 3) | ||
581 | #define HPI_ISTREAM_READ HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 4) | ||
582 | #define HPI_ISTREAM_START HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 5) | ||
583 | #define HPI_ISTREAM_STOP HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 6) | ||
584 | #define HPI_ISTREAM_RESET HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 7) | ||
585 | #define HPI_ISTREAM_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 8) | ||
586 | #define HPI_ISTREAM_QUERY_FORMAT HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 9) | ||
587 | #define HPI_ISTREAM_ANC_RESET HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 10) | ||
588 | #define HPI_ISTREAM_ANC_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 11) | ||
589 | #define HPI_ISTREAM_ANC_WRITE HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 12) | ||
590 | #define HPI_ISTREAM_HOSTBUFFER_ALLOC HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 13) | ||
591 | #define HPI_ISTREAM_HOSTBUFFER_FREE HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 14) | ||
592 | #define HPI_ISTREAM_GROUP_ADD HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 15) | ||
593 | #define HPI_ISTREAM_GROUP_GETMAP HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 16) | ||
594 | #define HPI_ISTREAM_GROUP_RESET HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 17) | ||
595 | #define HPI_ISTREAM_HOSTBUFFER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 18) | ||
596 | #define HPI_ISTREAM_WAIT_START HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 19) | ||
597 | #define HPI_ISTREAM_FUNCTION_COUNT 19 | ||
598 | /* MIXER */ | ||
599 | /* NOTE: | ||
600 | GET_NODE_INFO, SET_CONNECTION, GET_CONNECTIONS are not currently used */ | ||
601 | #define HPI_MIXER_OPEN HPI_MAKE_INDEX(HPI_OBJ_MIXER, 1) | ||
602 | #define HPI_MIXER_CLOSE HPI_MAKE_INDEX(HPI_OBJ_MIXER, 2) | ||
603 | #define HPI_MIXER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_MIXER, 3) | ||
604 | #define HPI_MIXER_GET_NODE_INFO HPI_MAKE_INDEX(HPI_OBJ_MIXER, 4) | ||
605 | #define HPI_MIXER_GET_CONTROL HPI_MAKE_INDEX(HPI_OBJ_MIXER, 5) | ||
606 | #define HPI_MIXER_SET_CONNECTION HPI_MAKE_INDEX(HPI_OBJ_MIXER, 6) | ||
607 | #define HPI_MIXER_GET_CONNECTIONS HPI_MAKE_INDEX(HPI_OBJ_MIXER, 7) | ||
608 | #define HPI_MIXER_GET_CONTROL_BY_INDEX HPI_MAKE_INDEX(HPI_OBJ_MIXER, 8) | ||
609 | #define HPI_MIXER_GET_CONTROL_ARRAY_BY_INDEX HPI_MAKE_INDEX(HPI_OBJ_MIXER, 9) | ||
610 | #define HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES HPI_MAKE_INDEX(HPI_OBJ_MIXER, 10) | ||
611 | #define HPI_MIXER_STORE HPI_MAKE_INDEX(HPI_OBJ_MIXER, 11) | ||
612 | #define HPI_MIXER_FUNCTION_COUNT 11 | ||
613 | /* MIXER CONTROLS */ | ||
614 | #define HPI_CONTROL_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 1) | ||
615 | #define HPI_CONTROL_GET_STATE HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 2) | ||
616 | #define HPI_CONTROL_SET_STATE HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 3) | ||
617 | #define HPI_CONTROL_FUNCTION_COUNT 3 | ||
618 | /* NONVOL MEMORY */ | ||
619 | #define HPI_NVMEMORY_OPEN HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 1) | ||
620 | #define HPI_NVMEMORY_READ_BYTE HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 2) | ||
621 | #define HPI_NVMEMORY_WRITE_BYTE HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 3) | ||
622 | #define HPI_NVMEMORY_FUNCTION_COUNT 3 | ||
623 | /* GPIO */ | ||
624 | #define HPI_GPIO_OPEN HPI_MAKE_INDEX(HPI_OBJ_GPIO, 1) | ||
625 | #define HPI_GPIO_READ_BIT HPI_MAKE_INDEX(HPI_OBJ_GPIO, 2) | ||
626 | #define HPI_GPIO_WRITE_BIT HPI_MAKE_INDEX(HPI_OBJ_GPIO, 3) | ||
627 | #define HPI_GPIO_READ_ALL HPI_MAKE_INDEX(HPI_OBJ_GPIO, 4) | ||
628 | #define HPI_GPIO_WRITE_STATUS HPI_MAKE_INDEX(HPI_OBJ_GPIO, 5) | ||
629 | #define HPI_GPIO_FUNCTION_COUNT 5 | ||
630 | /* ASYNC EVENT */ | ||
631 | #define HPI_ASYNCEVENT_OPEN HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 1) | ||
632 | #define HPI_ASYNCEVENT_CLOSE HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 2) | ||
633 | #define HPI_ASYNCEVENT_WAIT HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 3) | ||
634 | #define HPI_ASYNCEVENT_GETCOUNT HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 4) | ||
635 | #define HPI_ASYNCEVENT_GET HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 5) | ||
636 | #define HPI_ASYNCEVENT_SENDEVENTS HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 6) | ||
637 | #define HPI_ASYNCEVENT_FUNCTION_COUNT 6 | ||
638 | /* WATCH-DOG */ | ||
639 | #define HPI_WATCHDOG_OPEN HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 1) | ||
640 | #define HPI_WATCHDOG_SET_TIME HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 2) | ||
641 | #define HPI_WATCHDOG_PING HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 3) | ||
642 | /* CLOCK */ | ||
643 | #define HPI_CLOCK_OPEN HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 1) | ||
644 | #define HPI_CLOCK_SET_TIME HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 2) | ||
645 | #define HPI_CLOCK_GET_TIME HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 3) | ||
646 | /* PROFILE */ | ||
647 | #define HPI_PROFILE_OPEN_ALL HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 1) | ||
648 | #define HPI_PROFILE_START_ALL HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 2) | ||
649 | #define HPI_PROFILE_STOP_ALL HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 3) | ||
650 | #define HPI_PROFILE_GET HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 4) | ||
651 | #define HPI_PROFILE_GET_IDLECOUNT HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 5) | ||
652 | #define HPI_PROFILE_GET_NAME HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 6) | ||
653 | #define HPI_PROFILE_GET_UTILIZATION HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 7) | ||
654 | #define HPI_PROFILE_FUNCTION_COUNT 7 | ||
655 | /* ////////////////////////////////////////////////////////////////////// */ | ||
656 | /* PRIVATE ATTRIBUTES */ | ||
657 | |||
658 | /* ////////////////////////////////////////////////////////////////////// */ | ||
659 | /* STRUCTURES */ | ||
660 | #ifndef DISABLE_PRAGMA_PACK1 | ||
661 | #pragma pack(push, 1) | ||
662 | #endif | ||
663 | |||
664 | /** PCI bus resource */ | ||
665 | struct hpi_pci { | ||
666 | u32 __iomem *ap_mem_base[HPI_MAX_ADAPTER_MEM_SPACES]; | ||
667 | struct pci_dev *p_os_data; | ||
668 | |||
669 | #ifndef HPI64BIT /* keep structure size constant */ | ||
670 | u32 padding[HPI_MAX_ADAPTER_MEM_SPACES + 1]; | ||
671 | #endif | ||
672 | u16 vendor_id; | ||
673 | u16 device_id; | ||
674 | u16 subsys_vendor_id; | ||
675 | u16 subsys_device_id; | ||
676 | u16 bus_number; | ||
677 | u16 device_number; | ||
678 | u32 interrupt; | ||
679 | }; | ||
680 | |||
681 | struct hpi_resource { | ||
682 | union { | ||
683 | const struct hpi_pci *pci; | ||
684 | const char *net_if; | ||
685 | } r; | ||
686 | #ifndef HPI64BIT /* keep structure size constant */ | ||
687 | u32 pad_to64; | ||
688 | #endif | ||
689 | u16 bus_type; /* HPI_BUS_PNPISA, _PCI, _USB etc */ | ||
690 | u16 padding; | ||
691 | |||
692 | }; | ||
693 | |||
694 | /** Format info used inside struct hpi_message | ||
695 | Not the same as public API struct hpi_format */ | ||
696 | struct hpi_msg_format { | ||
697 | u32 sample_rate; | ||
698 | /**< 11025, 32000, 44100 ... */ | ||
699 | u32 bit_rate; /**< for MPEG */ | ||
700 | u32 attributes; | ||
701 | /**< Stereo/JointStereo/Mono */ | ||
702 | u16 channels; /**< 1,2..., (or ancillary mode or idle bit */ | ||
703 | u16 format; /**< HPI_FORMAT_PCM16, _MPEG etc. see \ref HPI_FORMATS. */ | ||
704 | }; | ||
705 | |||
706 | /** Buffer+format structure. | ||
707 | Must be kept 7 * 32 bits to match public struct hpi_datastruct */ | ||
708 | struct hpi_msg_data { | ||
709 | struct hpi_msg_format format; | ||
710 | u8 *pb_data; | ||
711 | #ifndef HPI64BIT | ||
712 | u32 padding; | ||
713 | #endif | ||
714 | u32 data_size; | ||
715 | }; | ||
716 | |||
717 | /** struct hpi_datastructure used up to 3.04 driver */ | ||
718 | struct hpi_data_legacy32 { | ||
719 | struct hpi_format format; | ||
720 | u32 pb_data; | ||
721 | u32 data_size; | ||
722 | }; | ||
723 | |||
724 | #ifdef HPI64BIT | ||
725 | /* Compatibility version of struct hpi_data*/ | ||
726 | struct hpi_data_compat32 { | ||
727 | struct hpi_msg_format format; | ||
728 | u32 pb_data; | ||
729 | u32 padding; | ||
730 | u32 data_size; | ||
731 | }; | ||
732 | #endif | ||
733 | |||
734 | struct hpi_buffer { | ||
735 | /** placehoder for backward compatability (see dwBufferSize) */ | ||
736 | struct hpi_msg_format reserved; | ||
737 | u32 command; /**< HPI_BUFFER_CMD_xxx*/ | ||
738 | u32 pci_address; /**< PCI physical address of buffer for DSP DMA */ | ||
739 | u32 buffer_size; /**< must line up with data_size of HPI_DATA*/ | ||
740 | }; | ||
741 | |||
742 | /*/////////////////////////////////////////////////////////////////////////// */ | ||
743 | /* This is used for background buffer bus mastering stream buffers. */ | ||
744 | struct hpi_hostbuffer_status { | ||
745 | u32 samples_processed; | ||
746 | u32 auxiliary_data_available; | ||
747 | u32 stream_state; | ||
748 | /* DSP index in to the host bus master buffer. */ | ||
749 | u32 dSP_index; | ||
750 | /* Host index in to the host bus master buffer. */ | ||
751 | u32 host_index; | ||
752 | u32 size_in_bytes; | ||
753 | }; | ||
754 | |||
755 | struct hpi_streamid { | ||
756 | u16 object_type; | ||
757 | /**< Type of object, HPI_OBJ_OSTREAM or HPI_OBJ_ISTREAM. */ | ||
758 | u16 stream_index; /**< outstream or instream index. */ | ||
759 | }; | ||
760 | |||
761 | struct hpi_punchinout { | ||
762 | u32 punch_in_sample; | ||
763 | u32 punch_out_sample; | ||
764 | }; | ||
765 | |||
766 | struct hpi_subsys_msg { | ||
767 | struct hpi_resource resource; | ||
768 | }; | ||
769 | |||
770 | struct hpi_subsys_res { | ||
771 | u32 version; | ||
772 | u32 data; /* used to return extended version */ | ||
773 | u16 num_adapters; /* number of adapters */ | ||
774 | u16 adapter_index; | ||
775 | u16 aw_adapter_list[HPI_MAX_ADAPTERS]; | ||
776 | }; | ||
777 | |||
778 | struct hpi_adapter_msg { | ||
779 | u32 adapter_mode; /* adapter mode */ | ||
780 | u16 assert_id; /* assert number for "test assert" call | ||
781 | object_index for find object call | ||
782 | query_or_set for hpi_adapter_set_mode_ex() */ | ||
783 | u16 object_type; /* for adapter find object call */ | ||
784 | }; | ||
785 | |||
786 | union hpi_adapterx_msg { | ||
787 | struct hpi_adapter_msg adapter; | ||
788 | struct { | ||
789 | u32 offset; | ||
790 | } query_flash; | ||
791 | struct { | ||
792 | u32 offset; | ||
793 | u32 length; | ||
794 | u32 key; | ||
795 | } start_flash; | ||
796 | struct { | ||
797 | u32 checksum; | ||
798 | u16 sequence; | ||
799 | u16 length; | ||
800 | u16 offset; /**< offset from start of msg to data */ | ||
801 | u16 unused; | ||
802 | } program_flash; | ||
803 | struct { | ||
804 | u16 property; | ||
805 | u16 parameter1; | ||
806 | u16 parameter2; | ||
807 | } property_set; | ||
808 | struct { | ||
809 | u16 index; | ||
810 | u16 what; | ||
811 | u16 property_index; | ||
812 | } property_enum; | ||
813 | struct { | ||
814 | u16 index; | ||
815 | } module_info; | ||
816 | struct { | ||
817 | u32 dsp_address; | ||
818 | u32 count_bytes; | ||
819 | } debug_read; | ||
820 | }; | ||
821 | |||
822 | struct hpi_adapter_res { | ||
823 | u32 serial_number; | ||
824 | u16 adapter_type; | ||
825 | u16 adapter_index; /* is this needed? also used for dsp_index */ | ||
826 | u16 num_instreams; | ||
827 | u16 num_outstreams; | ||
828 | u16 num_mixers; | ||
829 | u16 version; | ||
830 | u8 sz_adapter_assert[HPI_STRING_LEN]; | ||
831 | }; | ||
832 | |||
833 | union hpi_adapterx_res { | ||
834 | struct hpi_adapter_res adapter; | ||
835 | struct { | ||
836 | u32 checksum; | ||
837 | u32 length; | ||
838 | u32 version; | ||
839 | } query_flash; | ||
840 | struct { | ||
841 | u16 sequence; | ||
842 | } program_flash; | ||
843 | struct { | ||
844 | u16 parameter1; | ||
845 | u16 parameter2; | ||
846 | } property_get; | ||
847 | }; | ||
848 | |||
849 | struct hpi_stream_msg { | ||
850 | union { | ||
851 | struct hpi_msg_data data; | ||
852 | struct hpi_data_legacy32 data32; | ||
853 | u16 velocity; | ||
854 | struct hpi_punchinout pio; | ||
855 | u32 time_scale; | ||
856 | struct hpi_buffer buffer; | ||
857 | struct hpi_streamid stream; | ||
858 | } u; | ||
859 | }; | ||
860 | |||
861 | struct hpi_stream_res { | ||
862 | union { | ||
863 | struct { | ||
864 | /* size of hardware buffer */ | ||
865 | u32 buffer_size; | ||
866 | /* OutStream - data to play, | ||
867 | InStream - data recorded */ | ||
868 | u32 data_available; | ||
869 | /* OutStream - samples played, | ||
870 | InStream - samples recorded */ | ||
871 | u32 samples_transferred; | ||
872 | /* Adapter - OutStream - data to play, | ||
873 | InStream - data recorded */ | ||
874 | u32 auxiliary_data_available; | ||
875 | u16 state; /* HPI_STATE_PLAYING, _STATE_STOPPED */ | ||
876 | u16 padding; | ||
877 | } stream_info; | ||
878 | struct { | ||
879 | u32 buffer_size; | ||
880 | u32 data_available; | ||
881 | u32 samples_transfered; | ||
882 | u16 state; | ||
883 | u16 outstream_index; | ||
884 | u16 instream_index; | ||
885 | u16 padding; | ||
886 | u32 auxiliary_data_available; | ||
887 | } legacy_stream_info; | ||
888 | struct { | ||
889 | /* bitmap of grouped OutStreams */ | ||
890 | u32 outstream_group_map; | ||
891 | /* bitmap of grouped InStreams */ | ||
892 | u32 instream_group_map; | ||
893 | } group_info; | ||
894 | struct { | ||
895 | /* pointer to the buffer */ | ||
896 | u8 *p_buffer; | ||
897 | /* pointer to the hostbuffer status */ | ||
898 | struct hpi_hostbuffer_status *p_status; | ||
899 | } hostbuffer_info; | ||
900 | } u; | ||
901 | }; | ||
902 | |||
903 | struct hpi_mixer_msg { | ||
904 | u16 control_index; | ||
905 | u16 control_type; /* = HPI_CONTROL_METER _VOLUME etc */ | ||
906 | u16 padding1; /* maintain alignment of subsequent fields */ | ||
907 | u16 node_type1; /* = HPI_SOURCENODE_LINEIN etc */ | ||
908 | u16 node_index1; /* = 0..N */ | ||
909 | u16 node_type2; | ||
910 | u16 node_index2; | ||
911 | u16 padding2; /* round to 4 bytes */ | ||
912 | }; | ||
913 | |||
914 | struct hpi_mixer_res { | ||
915 | u16 src_node_type; /* = HPI_SOURCENODE_LINEIN etc */ | ||
916 | u16 src_node_index; /* = 0..N */ | ||
917 | u16 dst_node_type; | ||
918 | u16 dst_node_index; | ||
919 | /* Also controlType for MixerGetControlByIndex */ | ||
920 | u16 control_index; | ||
921 | /* may indicate which DSP the control is located on */ | ||
922 | u16 dsp_index; | ||
923 | }; | ||
924 | |||
925 | union hpi_mixerx_msg { | ||
926 | struct { | ||
927 | u16 starting_index; | ||
928 | u16 flags; | ||
929 | u32 length_in_bytes; /* length in bytes of p_data */ | ||
930 | u32 p_data; /* pointer to a data array */ | ||
931 | } gcabi; | ||
932 | struct { | ||
933 | u16 command; | ||
934 | u16 index; | ||
935 | } store; /* for HPI_MIXER_STORE message */ | ||
936 | }; | ||
937 | |||
938 | union hpi_mixerx_res { | ||
939 | struct { | ||
940 | u32 bytes_returned; /* size of items returned */ | ||
941 | u32 p_data; /* pointer to data array */ | ||
942 | u16 more_to_do; /* indicates if there is more to do */ | ||
943 | } gcabi; | ||
944 | }; | ||
945 | |||
946 | struct hpi_control_msg { | ||
947 | u16 attribute; /* control attribute or property */ | ||
948 | u16 saved_index; | ||
949 | u32 param1; /* generic parameter 1 */ | ||
950 | u32 param2; /* generic parameter 2 */ | ||
951 | short an_log_value[HPI_MAX_CHANNELS]; | ||
952 | }; | ||
953 | |||
954 | struct hpi_control_union_msg { | ||
955 | u16 attribute; /* control attribute or property */ | ||
956 | u16 saved_index; /* only used in ctrl save/restore */ | ||
957 | union { | ||
958 | struct { | ||
959 | u32 param1; /* generic parameter 1 */ | ||
960 | u32 param2; /* generic parameter 2 */ | ||
961 | short an_log_value[HPI_MAX_CHANNELS]; | ||
962 | } old; | ||
963 | union { | ||
964 | u32 frequency; | ||
965 | u32 gain; | ||
966 | u32 band; | ||
967 | u32 deemphasis; | ||
968 | u32 program; | ||
969 | struct { | ||
970 | u32 mode; | ||
971 | u32 value; | ||
972 | } mode; | ||
973 | } tuner; | ||
974 | } u; | ||
975 | }; | ||
976 | |||
977 | struct hpi_control_res { | ||
978 | /* Could make union. dwParam, anLogValue never used in same response */ | ||
979 | u32 param1; | ||
980 | u32 param2; | ||
981 | short an_log_value[HPI_MAX_CHANNELS]; | ||
982 | }; | ||
983 | |||
984 | union hpi_control_union_res { | ||
985 | struct { | ||
986 | u32 param1; | ||
987 | u32 param2; | ||
988 | short an_log_value[HPI_MAX_CHANNELS]; | ||
989 | } old; | ||
990 | union { | ||
991 | u32 band; | ||
992 | u32 frequency; | ||
993 | u32 gain; | ||
994 | u32 level; | ||
995 | u32 deemphasis; | ||
996 | struct { | ||
997 | u32 data[2]; | ||
998 | u32 bLER; | ||
999 | } rds; | ||
1000 | } tuner; | ||
1001 | struct { | ||
1002 | char sz_data[8]; | ||
1003 | u32 remaining_chars; | ||
1004 | } chars8; | ||
1005 | char c_data12[12]; | ||
1006 | }; | ||
1007 | |||
1008 | /* HPI_CONTROLX_STRUCTURES */ | ||
1009 | |||
1010 | /* Message */ | ||
1011 | |||
1012 | /** Used for all HMI variables where max length <= 8 bytes | ||
1013 | */ | ||
1014 | struct hpi_controlx_msg_cobranet_data { | ||
1015 | u32 hmi_address; | ||
1016 | u32 byte_count; | ||
1017 | u32 data[2]; | ||
1018 | }; | ||
1019 | |||
1020 | /** Used for string data, and for packet bridge | ||
1021 | */ | ||
1022 | struct hpi_controlx_msg_cobranet_bigdata { | ||
1023 | u32 hmi_address; | ||
1024 | u32 byte_count; | ||
1025 | u8 *pb_data; | ||
1026 | #ifndef HPI64BIT | ||
1027 | u32 padding; | ||
1028 | #endif | ||
1029 | }; | ||
1030 | |||
1031 | /** Used for PADS control reading of string fields. | ||
1032 | */ | ||
1033 | struct hpi_controlx_msg_pad_data { | ||
1034 | u32 field; | ||
1035 | u32 byte_count; | ||
1036 | u8 *pb_data; | ||
1037 | #ifndef HPI64BIT | ||
1038 | u32 padding; | ||
1039 | #endif | ||
1040 | }; | ||
1041 | |||
1042 | /** Used for generic data | ||
1043 | */ | ||
1044 | |||
1045 | struct hpi_controlx_msg_generic { | ||
1046 | u32 param1; | ||
1047 | u32 param2; | ||
1048 | }; | ||
1049 | |||
1050 | struct hpi_controlx_msg { | ||
1051 | u16 attribute; /* control attribute or property */ | ||
1052 | u16 saved_index; | ||
1053 | union { | ||
1054 | struct hpi_controlx_msg_cobranet_data cobranet_data; | ||
1055 | struct hpi_controlx_msg_cobranet_bigdata cobranet_bigdata; | ||
1056 | struct hpi_controlx_msg_generic generic; | ||
1057 | struct hpi_controlx_msg_pad_data pad_data; | ||
1058 | /*struct param_value universal_value; */ | ||
1059 | /* nothing extra to send for status read */ | ||
1060 | } u; | ||
1061 | }; | ||
1062 | |||
1063 | /* Response */ | ||
1064 | /** | ||
1065 | */ | ||
1066 | struct hpi_controlx_res_cobranet_data { | ||
1067 | u32 byte_count; | ||
1068 | u32 data[2]; | ||
1069 | }; | ||
1070 | |||
1071 | struct hpi_controlx_res_cobranet_bigdata { | ||
1072 | u32 byte_count; | ||
1073 | }; | ||
1074 | |||
1075 | struct hpi_controlx_res_cobranet_status { | ||
1076 | u32 status; | ||
1077 | u32 readable_size; | ||
1078 | u32 writeable_size; | ||
1079 | }; | ||
1080 | |||
1081 | struct hpi_controlx_res_generic { | ||
1082 | u32 param1; | ||
1083 | u32 param2; | ||
1084 | }; | ||
1085 | |||
1086 | struct hpi_controlx_res { | ||
1087 | union { | ||
1088 | struct hpi_controlx_res_cobranet_bigdata cobranet_bigdata; | ||
1089 | struct hpi_controlx_res_cobranet_data cobranet_data; | ||
1090 | struct hpi_controlx_res_cobranet_status cobranet_status; | ||
1091 | struct hpi_controlx_res_generic generic; | ||
1092 | /*struct param_info universal_info; */ | ||
1093 | /*struct param_value universal_value; */ | ||
1094 | } u; | ||
1095 | }; | ||
1096 | |||
1097 | struct hpi_nvmemory_msg { | ||
1098 | u16 address; | ||
1099 | u16 data; | ||
1100 | }; | ||
1101 | |||
1102 | struct hpi_nvmemory_res { | ||
1103 | u16 size_in_bytes; | ||
1104 | u16 data; | ||
1105 | }; | ||
1106 | |||
1107 | struct hpi_gpio_msg { | ||
1108 | u16 bit_index; | ||
1109 | u16 bit_data; | ||
1110 | }; | ||
1111 | |||
1112 | struct hpi_gpio_res { | ||
1113 | u16 number_input_bits; | ||
1114 | u16 number_output_bits; | ||
1115 | u16 bit_data[4]; | ||
1116 | }; | ||
1117 | |||
1118 | struct hpi_async_msg { | ||
1119 | u32 events; | ||
1120 | u16 maximum_events; | ||
1121 | u16 padding; | ||
1122 | }; | ||
1123 | |||
1124 | struct hpi_async_res { | ||
1125 | union { | ||
1126 | struct { | ||
1127 | u16 count; | ||
1128 | } count; | ||
1129 | struct { | ||
1130 | u32 events; | ||
1131 | u16 number_returned; | ||
1132 | u16 padding; | ||
1133 | } get; | ||
1134 | struct hpi_async_event event; | ||
1135 | } u; | ||
1136 | }; | ||
1137 | |||
1138 | struct hpi_watchdog_msg { | ||
1139 | u32 time_ms; | ||
1140 | }; | ||
1141 | |||
1142 | struct hpi_watchdog_res { | ||
1143 | u32 time_ms; | ||
1144 | }; | ||
1145 | |||
1146 | struct hpi_clock_msg { | ||
1147 | u16 hours; | ||
1148 | u16 minutes; | ||
1149 | u16 seconds; | ||
1150 | u16 milli_seconds; | ||
1151 | }; | ||
1152 | |||
1153 | struct hpi_clock_res { | ||
1154 | u16 size_in_bytes; | ||
1155 | u16 hours; | ||
1156 | u16 minutes; | ||
1157 | u16 seconds; | ||
1158 | u16 milli_seconds; | ||
1159 | u16 padding; | ||
1160 | }; | ||
1161 | |||
1162 | struct hpi_profile_msg { | ||
1163 | u16 bin_index; | ||
1164 | u16 padding; | ||
1165 | }; | ||
1166 | |||
1167 | struct hpi_profile_res_open { | ||
1168 | u16 max_profiles; | ||
1169 | }; | ||
1170 | |||
1171 | struct hpi_profile_res_time { | ||
1172 | u32 micro_seconds; | ||
1173 | u32 call_count; | ||
1174 | u32 max_micro_seconds; | ||
1175 | u32 min_micro_seconds; | ||
1176 | u16 seconds; | ||
1177 | }; | ||
1178 | |||
1179 | struct hpi_profile_res_name { | ||
1180 | u8 sz_name[32]; | ||
1181 | }; | ||
1182 | |||
1183 | struct hpi_profile_res { | ||
1184 | union { | ||
1185 | struct hpi_profile_res_open o; | ||
1186 | struct hpi_profile_res_time t; | ||
1187 | struct hpi_profile_res_name n; | ||
1188 | } u; | ||
1189 | }; | ||
1190 | |||
1191 | struct hpi_message_header { | ||
1192 | u16 size; /* total size in bytes */ | ||
1193 | u8 type; /* HPI_TYPE_MESSAGE */ | ||
1194 | u8 version; /* message version */ | ||
1195 | u16 object; /* HPI_OBJ_* */ | ||
1196 | u16 function; /* HPI_SUBSYS_xxx, HPI_ADAPTER_xxx */ | ||
1197 | u16 adapter_index; /* the adapter index */ | ||
1198 | u16 obj_index; /* */ | ||
1199 | }; | ||
1200 | |||
1201 | struct hpi_message { | ||
1202 | /* following fields must match HPI_MESSAGE_HEADER */ | ||
1203 | u16 size; /* total size in bytes */ | ||
1204 | u8 type; /* HPI_TYPE_MESSAGE */ | ||
1205 | u8 version; /* message version */ | ||
1206 | u16 object; /* HPI_OBJ_* */ | ||
1207 | u16 function; /* HPI_SUBSYS_xxx, HPI_ADAPTER_xxx */ | ||
1208 | u16 adapter_index; /* the adapter index */ | ||
1209 | u16 obj_index; /* */ | ||
1210 | union { | ||
1211 | struct hpi_subsys_msg s; | ||
1212 | struct hpi_adapter_msg a; | ||
1213 | union hpi_adapterx_msg ax; | ||
1214 | struct hpi_stream_msg d; | ||
1215 | struct hpi_mixer_msg m; | ||
1216 | union hpi_mixerx_msg mx; /* extended mixer; */ | ||
1217 | struct hpi_control_msg c; /* mixer control; */ | ||
1218 | /* identical to struct hpi_control_msg, | ||
1219 | but field naming is improved */ | ||
1220 | struct hpi_control_union_msg cu; | ||
1221 | struct hpi_controlx_msg cx; /* extended mixer control; */ | ||
1222 | struct hpi_nvmemory_msg n; | ||
1223 | struct hpi_gpio_msg l; /* digital i/o */ | ||
1224 | struct hpi_watchdog_msg w; | ||
1225 | struct hpi_clock_msg t; /* dsp time */ | ||
1226 | struct hpi_profile_msg p; | ||
1227 | struct hpi_async_msg as; | ||
1228 | char fixed_size[32]; | ||
1229 | } u; | ||
1230 | }; | ||
1231 | |||
1232 | #define HPI_MESSAGE_SIZE_BY_OBJECT { \ | ||
1233 | sizeof(struct hpi_message_header) , /* default, no object type 0 */ \ | ||
1234 | sizeof(struct hpi_message_header) + sizeof(struct hpi_subsys_msg),\ | ||
1235 | sizeof(struct hpi_message_header) + sizeof(union hpi_adapterx_msg),\ | ||
1236 | sizeof(struct hpi_message_header) + sizeof(struct hpi_stream_msg),\ | ||
1237 | sizeof(struct hpi_message_header) + sizeof(struct hpi_stream_msg),\ | ||
1238 | sizeof(struct hpi_message_header) + sizeof(struct hpi_mixer_msg),\ | ||
1239 | sizeof(struct hpi_message_header) , /* no node message */ \ | ||
1240 | sizeof(struct hpi_message_header) + sizeof(struct hpi_control_msg),\ | ||
1241 | sizeof(struct hpi_message_header) + sizeof(struct hpi_nvmemory_msg),\ | ||
1242 | sizeof(struct hpi_message_header) + sizeof(struct hpi_gpio_msg),\ | ||
1243 | sizeof(struct hpi_message_header) + sizeof(struct hpi_watchdog_msg),\ | ||
1244 | sizeof(struct hpi_message_header) + sizeof(struct hpi_clock_msg),\ | ||
1245 | sizeof(struct hpi_message_header) + sizeof(struct hpi_profile_msg),\ | ||
1246 | sizeof(struct hpi_message_header) + sizeof(struct hpi_controlx_msg),\ | ||
1247 | sizeof(struct hpi_message_header) + sizeof(struct hpi_async_msg) \ | ||
1248 | } | ||
1249 | |||
1250 | struct hpi_response_header { | ||
1251 | u16 size; | ||
1252 | u8 type; /* HPI_TYPE_RESPONSE */ | ||
1253 | u8 version; /* response version */ | ||
1254 | u16 object; /* HPI_OBJ_* */ | ||
1255 | u16 function; /* HPI_SUBSYS_xxx, HPI_ADAPTER_xxx */ | ||
1256 | u16 error; /* HPI_ERROR_xxx */ | ||
1257 | u16 specific_error; /* adapter specific error */ | ||
1258 | }; | ||
1259 | |||
1260 | struct hpi_response { | ||
1261 | /* following fields must match HPI_RESPONSE_HEADER */ | ||
1262 | u16 size; | ||
1263 | u8 type; /* HPI_TYPE_RESPONSE */ | ||
1264 | u8 version; /* response version */ | ||
1265 | u16 object; /* HPI_OBJ_* */ | ||
1266 | u16 function; /* HPI_SUBSYS_xxx, HPI_ADAPTER_xxx */ | ||
1267 | u16 error; /* HPI_ERROR_xxx */ | ||
1268 | u16 specific_error; /* adapter specific error */ | ||
1269 | union { | ||
1270 | struct hpi_subsys_res s; | ||
1271 | struct hpi_adapter_res a; | ||
1272 | union hpi_adapterx_res ax; | ||
1273 | struct hpi_stream_res d; | ||
1274 | struct hpi_mixer_res m; | ||
1275 | union hpi_mixerx_res mx; /* extended mixer; */ | ||
1276 | struct hpi_control_res c; /* mixer control; */ | ||
1277 | /* identical to hpi_control_res, but field naming is improved */ | ||
1278 | union hpi_control_union_res cu; | ||
1279 | struct hpi_controlx_res cx; /* extended mixer control; */ | ||
1280 | struct hpi_nvmemory_res n; | ||
1281 | struct hpi_gpio_res l; /* digital i/o */ | ||
1282 | struct hpi_watchdog_res w; | ||
1283 | struct hpi_clock_res t; /* dsp time */ | ||
1284 | struct hpi_profile_res p; | ||
1285 | struct hpi_async_res as; | ||
1286 | u8 bytes[52]; | ||
1287 | } u; | ||
1288 | }; | ||
1289 | |||
1290 | #define HPI_RESPONSE_SIZE_BY_OBJECT { \ | ||
1291 | sizeof(struct hpi_response_header) ,/* default, no object type 0 */ \ | ||
1292 | sizeof(struct hpi_response_header) + sizeof(struct hpi_subsys_res),\ | ||
1293 | sizeof(struct hpi_response_header) + sizeof(union hpi_adapterx_res),\ | ||
1294 | sizeof(struct hpi_response_header) + sizeof(struct hpi_stream_res),\ | ||
1295 | sizeof(struct hpi_response_header) + sizeof(struct hpi_stream_res),\ | ||
1296 | sizeof(struct hpi_response_header) + sizeof(struct hpi_mixer_res),\ | ||
1297 | sizeof(struct hpi_response_header) , /* no node response */ \ | ||
1298 | sizeof(struct hpi_response_header) + sizeof(struct hpi_control_res),\ | ||
1299 | sizeof(struct hpi_response_header) + sizeof(struct hpi_nvmemory_res),\ | ||
1300 | sizeof(struct hpi_response_header) + sizeof(struct hpi_gpio_res),\ | ||
1301 | sizeof(struct hpi_response_header) + sizeof(struct hpi_watchdog_res),\ | ||
1302 | sizeof(struct hpi_response_header) + sizeof(struct hpi_clock_res),\ | ||
1303 | sizeof(struct hpi_response_header) + sizeof(struct hpi_profile_res),\ | ||
1304 | sizeof(struct hpi_response_header) + sizeof(struct hpi_controlx_res),\ | ||
1305 | sizeof(struct hpi_response_header) + sizeof(struct hpi_async_res) \ | ||
1306 | } | ||
1307 | |||
1308 | /*********************** version 1 message/response *****************************/ | ||
1309 | #define HPINET_ETHERNET_DATA_SIZE (1500) | ||
1310 | #define HPINET_IP_HDR_SIZE (20) | ||
1311 | #define HPINET_IP_DATA_SIZE (HPINET_ETHERNET_DATA_SIZE - HPINET_IP_HDR_SIZE) | ||
1312 | #define HPINET_UDP_HDR_SIZE (8) | ||
1313 | #define HPINET_UDP_DATA_SIZE (HPINET_IP_DATA_SIZE - HPINET_UDP_HDR_SIZE) | ||
1314 | #define HPINET_ASI_HDR_SIZE (2) | ||
1315 | #define HPINET_ASI_DATA_SIZE (HPINET_UDP_DATA_SIZE - HPINET_ASI_HDR_SIZE) | ||
1316 | |||
1317 | #define HPI_MAX_PAYLOAD_SIZE (HPINET_ASI_DATA_SIZE - 2) | ||
1318 | |||
1319 | /* New style message/response, but still V0 compatible */ | ||
1320 | struct hpi_msg_adapter_get_info { | ||
1321 | struct hpi_message_header h; | ||
1322 | }; | ||
1323 | |||
1324 | struct hpi_res_adapter_get_info { | ||
1325 | struct hpi_response_header h; /*v0 */ | ||
1326 | struct hpi_adapter_res p; | ||
1327 | }; | ||
1328 | |||
1329 | /* padding is so these are same size as v0 hpi_message */ | ||
1330 | struct hpi_msg_adapter_query_flash { | ||
1331 | struct hpi_message_header h; | ||
1332 | u32 offset; | ||
1333 | u8 pad_to_version0_size[sizeof(struct hpi_message) - /* V0 res */ | ||
1334 | sizeof(struct hpi_message_header) - 1 * sizeof(u32)]; | ||
1335 | }; | ||
1336 | |||
1337 | /* padding is so these are same size as v0 hpi_response */ | ||
1338 | struct hpi_res_adapter_query_flash { | ||
1339 | struct hpi_response_header h; | ||
1340 | u32 checksum; | ||
1341 | u32 length; | ||
1342 | u32 version; | ||
1343 | u8 pad_to_version0_size[sizeof(struct hpi_response) - /* V0 res */ | ||
1344 | sizeof(struct hpi_response_header) - 3 * sizeof(u32)]; | ||
1345 | }; | ||
1346 | |||
1347 | struct hpi_msg_adapter_start_flash { | ||
1348 | struct hpi_message_header h; | ||
1349 | u32 offset; | ||
1350 | u32 length; | ||
1351 | u32 key; | ||
1352 | u8 pad_to_version0_size[sizeof(struct hpi_message) - /* V0 res */ | ||
1353 | sizeof(struct hpi_message_header) - 3 * sizeof(u32)]; | ||
1354 | }; | ||
1355 | |||
1356 | struct hpi_res_adapter_start_flash { | ||
1357 | struct hpi_response_header h; | ||
1358 | u8 pad_to_version0_size[sizeof(struct hpi_response) - /* V0 res */ | ||
1359 | sizeof(struct hpi_response_header)]; | ||
1360 | }; | ||
1361 | |||
1362 | struct hpi_msg_adapter_program_flash_payload { | ||
1363 | u32 checksum; | ||
1364 | u16 sequence; | ||
1365 | u16 length; | ||
1366 | u16 offset; /**< offset from start of msg to data */ | ||
1367 | u16 unused; | ||
1368 | /* ensure sizeof(header + payload) == sizeof(hpi_message_V0) | ||
1369 | because old firmware expects data after message of this size */ | ||
1370 | u8 pad_to_version0_size[sizeof(struct hpi_message) - /* V0 message */ | ||
1371 | sizeof(struct hpi_message_header) - sizeof(u32) - | ||
1372 | 4 * sizeof(u16)]; | ||
1373 | }; | ||
1374 | |||
1375 | struct hpi_msg_adapter_program_flash { | ||
1376 | struct hpi_message_header h; | ||
1377 | struct hpi_msg_adapter_program_flash_payload p; | ||
1378 | u32 data[256]; | ||
1379 | }; | ||
1380 | |||
1381 | struct hpi_res_adapter_program_flash { | ||
1382 | struct hpi_response_header h; | ||
1383 | u16 sequence; | ||
1384 | u8 pad_to_version0_size[sizeof(struct hpi_response) - /* V0 res */ | ||
1385 | sizeof(struct hpi_response_header) - sizeof(u16)]; | ||
1386 | }; | ||
1387 | |||
1388 | #if 1 | ||
1389 | #define hpi_message_header_v1 hpi_message_header | ||
1390 | #define hpi_response_header_v1 hpi_response_header | ||
1391 | #else | ||
1392 | /* V1 headers in Addition to v0 headers */ | ||
1393 | struct hpi_message_header_v1 { | ||
1394 | struct hpi_message_header h0; | ||
1395 | /* struct { | ||
1396 | } h1; */ | ||
1397 | }; | ||
1398 | |||
1399 | struct hpi_response_header_v1 { | ||
1400 | struct hpi_response_header h0; | ||
1401 | struct { | ||
1402 | u16 adapter_index; /* the adapter index */ | ||
1403 | u16 obj_index; /* object index */ | ||
1404 | } h1; | ||
1405 | }; | ||
1406 | #endif | ||
1407 | |||
1408 | /* STRV HPI Packet */ | ||
1409 | struct hpi_msg_strv { | ||
1410 | struct hpi_message_header h; | ||
1411 | struct hpi_entity strv; | ||
1412 | }; | ||
1413 | |||
1414 | struct hpi_res_strv { | ||
1415 | struct hpi_response_header h; | ||
1416 | struct hpi_entity strv; | ||
1417 | }; | ||
1418 | #define MIN_STRV_PACKET_SIZE sizeof(struct hpi_res_strv) | ||
1419 | |||
1420 | struct hpi_msg_payload_v0 { | ||
1421 | struct hpi_message_header h; | ||
1422 | union { | ||
1423 | struct hpi_subsys_msg s; | ||
1424 | struct hpi_adapter_msg a; | ||
1425 | union hpi_adapterx_msg ax; | ||
1426 | struct hpi_stream_msg d; | ||
1427 | struct hpi_mixer_msg m; | ||
1428 | union hpi_mixerx_msg mx; | ||
1429 | struct hpi_control_msg c; | ||
1430 | struct hpi_control_union_msg cu; | ||
1431 | struct hpi_controlx_msg cx; | ||
1432 | struct hpi_nvmemory_msg n; | ||
1433 | struct hpi_gpio_msg l; | ||
1434 | struct hpi_watchdog_msg w; | ||
1435 | struct hpi_clock_msg t; | ||
1436 | struct hpi_profile_msg p; | ||
1437 | struct hpi_async_msg as; | ||
1438 | } u; | ||
1439 | }; | ||
1440 | |||
1441 | struct hpi_res_payload_v0 { | ||
1442 | struct hpi_response_header h; | ||
1443 | union { | ||
1444 | struct hpi_subsys_res s; | ||
1445 | struct hpi_adapter_res a; | ||
1446 | union hpi_adapterx_res ax; | ||
1447 | struct hpi_stream_res d; | ||
1448 | struct hpi_mixer_res m; | ||
1449 | union hpi_mixerx_res mx; | ||
1450 | struct hpi_control_res c; | ||
1451 | union hpi_control_union_res cu; | ||
1452 | struct hpi_controlx_res cx; | ||
1453 | struct hpi_nvmemory_res n; | ||
1454 | struct hpi_gpio_res l; | ||
1455 | struct hpi_watchdog_res w; | ||
1456 | struct hpi_clock_res t; | ||
1457 | struct hpi_profile_res p; | ||
1458 | struct hpi_async_res as; | ||
1459 | } u; | ||
1460 | }; | ||
1461 | |||
1462 | union hpi_message_buffer_v1 { | ||
1463 | struct hpi_message m0; /* version 0 */ | ||
1464 | struct hpi_message_header_v1 h; | ||
1465 | unsigned char buf[HPI_MAX_PAYLOAD_SIZE]; | ||
1466 | }; | ||
1467 | |||
1468 | union hpi_response_buffer_v1 { | ||
1469 | struct hpi_response r0; /* version 0 */ | ||
1470 | struct hpi_response_header_v1 h; | ||
1471 | unsigned char buf[HPI_MAX_PAYLOAD_SIZE]; | ||
1472 | }; | ||
1473 | |||
1474 | compile_time_assert((sizeof(union hpi_message_buffer_v1) <= | ||
1475 | HPI_MAX_PAYLOAD_SIZE), message_buffer_ok); | ||
1476 | compile_time_assert((sizeof(union hpi_response_buffer_v1) <= | ||
1477 | HPI_MAX_PAYLOAD_SIZE), response_buffer_ok); | ||
1478 | |||
1479 | /*////////////////////////////////////////////////////////////////////////// */ | ||
1480 | /* declarations for compact control calls */ | ||
1481 | struct hpi_control_defn { | ||
1482 | u8 type; | ||
1483 | u8 channels; | ||
1484 | u8 src_node_type; | ||
1485 | u8 src_node_index; | ||
1486 | u8 dest_node_type; | ||
1487 | u8 dest_node_index; | ||
1488 | }; | ||
1489 | |||
1490 | /*////////////////////////////////////////////////////////////////////////// */ | ||
1491 | /* declarations for control caching (internal to HPI<->DSP interaction) */ | ||
1492 | |||
1493 | /** A compact representation of (part of) a controls state. | ||
1494 | Used for efficient transfer of the control state | ||
1495 | between DSP and host or across a network | ||
1496 | */ | ||
1497 | struct hpi_control_cache_info { | ||
1498 | /** one of HPI_CONTROL_* */ | ||
1499 | u8 control_type; | ||
1500 | /** The total size of cached information in 32-bit words. */ | ||
1501 | u8 size_in32bit_words; | ||
1502 | /** The original index of the control on the DSP */ | ||
1503 | u16 control_index; | ||
1504 | }; | ||
1505 | |||
1506 | struct hpi_control_cache_single { | ||
1507 | struct hpi_control_cache_info i; | ||
1508 | union { | ||
1509 | struct { /* volume */ | ||
1510 | u16 an_log[2]; | ||
1511 | } v; | ||
1512 | struct { /* peak meter */ | ||
1513 | u16 an_log_peak[2]; | ||
1514 | u16 an_logRMS[2]; | ||
1515 | } p; | ||
1516 | struct { /* channel mode */ | ||
1517 | u16 mode; | ||
1518 | } m; | ||
1519 | struct { /* multiplexer */ | ||
1520 | u16 source_node_type; | ||
1521 | u16 source_node_index; | ||
1522 | } x; | ||
1523 | struct { /* level/trim */ | ||
1524 | u16 an_log[2]; | ||
1525 | } l; | ||
1526 | struct { /* tuner - partial caching. | ||
1527 | some attributes go to the DSP. */ | ||
1528 | u32 freq_ink_hz; | ||
1529 | u16 band; | ||
1530 | u16 level; | ||
1531 | } t; | ||
1532 | struct { /* AESEBU rx status */ | ||
1533 | u32 error_status; | ||
1534 | u32 source; | ||
1535 | } aes3rx; | ||
1536 | struct { /* AESEBU tx */ | ||
1537 | u32 format; | ||
1538 | } aes3tx; | ||
1539 | struct { /* tone detector */ | ||
1540 | u16 state; | ||
1541 | } tone; | ||
1542 | struct { /* silence detector */ | ||
1543 | u32 state; | ||
1544 | u32 count; | ||
1545 | } silence; | ||
1546 | struct { /* sample clock */ | ||
1547 | u16 source; | ||
1548 | u16 source_index; | ||
1549 | u32 sample_rate; | ||
1550 | } clk; | ||
1551 | struct { /* microphone control */ | ||
1552 | u16 state; | ||
1553 | } phantom_power; | ||
1554 | struct { /* generic control */ | ||
1555 | u32 dw1; | ||
1556 | u32 dw2; | ||
1557 | } g; | ||
1558 | } u; | ||
1559 | }; | ||
1560 | |||
1561 | struct hpi_control_cache_pad { | ||
1562 | struct hpi_control_cache_info i; | ||
1563 | u32 field_valid_flags; | ||
1564 | u8 c_channel[8]; | ||
1565 | u8 c_artist[40]; | ||
1566 | u8 c_title[40]; | ||
1567 | u8 c_comment[200]; | ||
1568 | u32 pTY; | ||
1569 | u32 pI; | ||
1570 | u32 traffic_supported; | ||
1571 | u32 traffic_anouncement; | ||
1572 | }; | ||
1573 | |||
1574 | /*/////////////////////////////////////////////////////////////////////////// */ | ||
1575 | /* declarations for 2^N sized FIFO buffer (internal to HPI<->DSP interaction) */ | ||
1576 | struct hpi_fifo_buffer { | ||
1577 | u32 size; | ||
1578 | u32 dSP_index; | ||
1579 | u32 host_index; | ||
1580 | }; | ||
1581 | |||
1582 | #ifndef DISABLE_PRAGMA_PACK1 | ||
1583 | #pragma pack(pop) | ||
1584 | #endif | ||
1585 | |||
1586 | /* skip host side function declarations for DSP | ||
1587 | compile and documentation extraction */ | ||
1588 | |||
1589 | char hpi_handle_object(const u32 handle); | ||
1590 | |||
1591 | void hpi_handle_to_indexes(const u32 handle, u16 *pw_adapter_index, | ||
1592 | u16 *pw_object_index); | ||
1593 | |||
1594 | u32 hpi_indexes_to_handle(const char c_object, const u16 adapter_index, | ||
1595 | const u16 object_index); | ||
1596 | |||
1597 | /*////////////////////////////////////////////////////////////////////////// */ | ||
1598 | |||
1599 | /* main HPI entry point */ | ||
1600 | hpi_handler_func hpi_send_recv; | ||
1601 | |||
1602 | /* UDP message */ | ||
1603 | void hpi_send_recvUDP(struct hpi_message *phm, struct hpi_response *phr, | ||
1604 | const unsigned int timeout); | ||
1605 | |||
1606 | /* used in PnP OS/driver */ | ||
1607 | u16 hpi_subsys_create_adapter(const struct hpi_hsubsys *ph_subsys, | ||
1608 | const struct hpi_resource *p_resource, u16 *pw_adapter_index); | ||
1609 | |||
1610 | u16 hpi_subsys_delete_adapter(const struct hpi_hsubsys *ph_subsys, | ||
1611 | u16 adapter_index); | ||
1612 | |||
1613 | u16 hpi_outstream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys, | ||
1614 | u32 h_outstream, u8 **pp_buffer, | ||
1615 | struct hpi_hostbuffer_status **pp_status); | ||
1616 | |||
1617 | u16 hpi_instream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys, | ||
1618 | u32 h_instream, u8 **pp_buffer, | ||
1619 | struct hpi_hostbuffer_status **pp_status); | ||
1620 | |||
1621 | u16 hpi_adapter_restart(u16 adapter_index); | ||
1622 | |||
1623 | /* | ||
1624 | The following 3 functions were last declared in header files for | ||
1625 | driver 3.10. HPI_ControlQuery() used to be the recommended way | ||
1626 | of getting a volume range. Declared here for binary asihpi32.dll | ||
1627 | compatibility. | ||
1628 | */ | ||
1629 | |||
1630 | void hpi_format_to_msg(struct hpi_msg_format *pMF, | ||
1631 | const struct hpi_format *pF); | ||
1632 | void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR); | ||
1633 | |||
1634 | /*////////////////////////////////////////////////////////////////////////// */ | ||
1635 | /* declarations for individual HPI entry points */ | ||
1636 | hpi_handler_func HPI_1000; | ||
1637 | hpi_handler_func HPI_6000; | ||
1638 | hpi_handler_func HPI_6205; | ||
1639 | hpi_handler_func HPI_COMMON; | ||
1640 | |||
1641 | #endif /* _HPI_INTERNAL_H_ */ | ||
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c new file mode 100644 index 00000000000..565102cae4f --- /dev/null +++ b/sound/pci/asihpi/hpicmn.c | |||
@@ -0,0 +1,643 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | \file hpicmn.c | ||
20 | |||
21 | Common functions used by hpixxxx.c modules | ||
22 | |||
23 | (C) Copyright AudioScience Inc. 1998-2003 | ||
24 | *******************************************************************************/ | ||
25 | #define SOURCEFILE_NAME "hpicmn.c" | ||
26 | |||
27 | #include "hpi_internal.h" | ||
28 | #include "hpidebug.h" | ||
29 | #include "hpicmn.h" | ||
30 | |||
31 | struct hpi_adapters_list { | ||
32 | struct hpios_spinlock list_lock; | ||
33 | struct hpi_adapter_obj adapter[HPI_MAX_ADAPTERS]; | ||
34 | u16 gw_num_adapters; | ||
35 | }; | ||
36 | |||
37 | static struct hpi_adapters_list adapters; | ||
38 | |||
39 | /** | ||
40 | * Given an HPI Message that was sent out and a response that was received, | ||
41 | * validate that the response has the correct fields filled in, | ||
42 | * i.e ObjectType, Function etc | ||
43 | **/ | ||
44 | u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr) | ||
45 | { | ||
46 | u16 error = 0; | ||
47 | |||
48 | if ((phr->type != HPI_TYPE_RESPONSE) | ||
49 | || (phr->object != phm->object) | ||
50 | || (phr->function != phm->function)) | ||
51 | error = HPI_ERROR_INVALID_RESPONSE; | ||
52 | |||
53 | return error; | ||
54 | } | ||
55 | |||
56 | u16 hpi_add_adapter(struct hpi_adapter_obj *pao) | ||
57 | { | ||
58 | u16 retval = 0; | ||
59 | /*HPI_ASSERT(pao->wAdapterType); */ | ||
60 | |||
61 | hpios_alistlock_lock(&adapters); | ||
62 | |||
63 | if (pao->index >= HPI_MAX_ADAPTERS) { | ||
64 | retval = HPI_ERROR_BAD_ADAPTER_NUMBER; | ||
65 | goto unlock; | ||
66 | } | ||
67 | |||
68 | if (adapters.adapter[pao->index].adapter_type) { | ||
69 | { | ||
70 | retval = HPI_DUPLICATE_ADAPTER_NUMBER; | ||
71 | goto unlock; | ||
72 | } | ||
73 | } | ||
74 | adapters.adapter[pao->index] = *pao; | ||
75 | hpios_dsplock_init(&adapters.adapter[pao->index]); | ||
76 | adapters.gw_num_adapters++; | ||
77 | |||
78 | unlock: | ||
79 | hpios_alistlock_un_lock(&adapters); | ||
80 | return retval; | ||
81 | } | ||
82 | |||
83 | void hpi_delete_adapter(struct hpi_adapter_obj *pao) | ||
84 | { | ||
85 | memset(pao, 0, sizeof(struct hpi_adapter_obj)); | ||
86 | |||
87 | hpios_alistlock_lock(&adapters); | ||
88 | adapters.gw_num_adapters--; /* dec the number of adapters */ | ||
89 | hpios_alistlock_un_lock(&adapters); | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * FindAdapter returns a pointer to the struct hpi_adapter_obj with | ||
94 | * index wAdapterIndex in an HPI_ADAPTERS_LIST structure. | ||
95 | * | ||
96 | */ | ||
97 | struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index) | ||
98 | { | ||
99 | struct hpi_adapter_obj *pao = NULL; | ||
100 | |||
101 | if (adapter_index >= HPI_MAX_ADAPTERS) { | ||
102 | HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d ", | ||
103 | adapter_index); | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | pao = &adapters.adapter[adapter_index]; | ||
108 | if (pao->adapter_type != 0) { | ||
109 | /* | ||
110 | HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n", | ||
111 | wAdapterIndex); | ||
112 | */ | ||
113 | return pao; | ||
114 | } else { | ||
115 | /* | ||
116 | HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n", | ||
117 | wAdapterIndex); | ||
118 | */ | ||
119 | return NULL; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * | ||
125 | * wipe an HPI_ADAPTERS_LIST structure. | ||
126 | * | ||
127 | **/ | ||
128 | static void wipe_adapter_list(void | ||
129 | ) | ||
130 | { | ||
131 | memset(&adapters, 0, sizeof(adapters)); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * SubSysGetAdapters fills awAdapterList in an struct hpi_response structure | ||
136 | * with all adapters in the given HPI_ADAPTERS_LIST. | ||
137 | * | ||
138 | */ | ||
139 | static void subsys_get_adapters(struct hpi_response *phr) | ||
140 | { | ||
141 | /* fill in the response adapter array with the position */ | ||
142 | /* identified by the adapter number/index of the adapters in */ | ||
143 | /* this HPI */ | ||
144 | /* i.e. if we have an A120 with it's jumper set to */ | ||
145 | /* Adapter Number 2 then put an Adapter type A120 in the */ | ||
146 | /* array in position 1 */ | ||
147 | /* NOTE: AdapterNumber is 1..N, Index is 0..N-1 */ | ||
148 | |||
149 | /* input: NONE */ | ||
150 | /* output: wNumAdapters */ | ||
151 | /* awAdapter[] */ | ||
152 | /* */ | ||
153 | |||
154 | short i; | ||
155 | struct hpi_adapter_obj *pao = NULL; | ||
156 | |||
157 | HPI_DEBUG_LOG(VERBOSE, "subsys_get_adapters\n"); | ||
158 | |||
159 | /* for each adapter, place it's type in the position of the array */ | ||
160 | /* corresponding to it's adapter number */ | ||
161 | for (i = 0; i < adapters.gw_num_adapters; i++) { | ||
162 | pao = &adapters.adapter[i]; | ||
163 | if (phr->u.s.aw_adapter_list[pao->index] != 0) { | ||
164 | phr->error = HPI_DUPLICATE_ADAPTER_NUMBER; | ||
165 | phr->specific_error = pao->index; | ||
166 | return; | ||
167 | } | ||
168 | phr->u.s.aw_adapter_list[pao->index] = pao->adapter_type; | ||
169 | } | ||
170 | |||
171 | phr->u.s.num_adapters = adapters.gw_num_adapters; | ||
172 | phr->error = 0; /* the function completed OK; */ | ||
173 | } | ||
174 | |||
175 | static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) | ||
176 | { | ||
177 | unsigned int i; | ||
178 | int cached = 0; | ||
179 | if (!pC) | ||
180 | return 0; | ||
181 | if ((!pC->init) && (pC->p_cache != NULL) && (pC->control_count) | ||
182 | && (pC->cache_size_in_bytes) | ||
183 | ) { | ||
184 | u32 *p_master_cache; | ||
185 | pC->init = 1; | ||
186 | |||
187 | p_master_cache = (u32 *)pC->p_cache; | ||
188 | HPI_DEBUG_LOG(VERBOSE, "check %d controls\n", | ||
189 | pC->control_count); | ||
190 | for (i = 0; i < pC->control_count; i++) { | ||
191 | struct hpi_control_cache_info *info = | ||
192 | (struct hpi_control_cache_info *) | ||
193 | p_master_cache; | ||
194 | |||
195 | if (info->control_type) { | ||
196 | pC->p_info[i] = info; | ||
197 | cached++; | ||
198 | } else | ||
199 | pC->p_info[i] = NULL; | ||
200 | |||
201 | if (info->size_in32bit_words) | ||
202 | p_master_cache += info->size_in32bit_words; | ||
203 | else | ||
204 | p_master_cache += | ||
205 | sizeof(struct | ||
206 | hpi_control_cache_single) / | ||
207 | sizeof(u32); | ||
208 | |||
209 | HPI_DEBUG_LOG(VERBOSE, | ||
210 | "cached %d, pinfo %p index %d type %d\n", | ||
211 | cached, pC->p_info[i], info->control_index, | ||
212 | info->control_type); | ||
213 | } | ||
214 | /* | ||
215 | We didn't find anything to cache, so try again later ! | ||
216 | */ | ||
217 | if (!cached) | ||
218 | pC->init = 0; | ||
219 | } | ||
220 | return pC->init; | ||
221 | } | ||
222 | |||
223 | /** Find a control. | ||
224 | */ | ||
225 | static short find_control(struct hpi_message *phm, | ||
226 | struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI, | ||
227 | u16 *pw_control_index) | ||
228 | { | ||
229 | *pw_control_index = phm->obj_index; | ||
230 | |||
231 | if (!control_cache_alloc_check(p_cache)) { | ||
232 | HPI_DEBUG_LOG(VERBOSE, | ||
233 | "control_cache_alloc_check() failed. adap%d ci%d\n", | ||
234 | phm->adapter_index, *pw_control_index); | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | *pI = p_cache->p_info[*pw_control_index]; | ||
239 | if (!*pI) { | ||
240 | HPI_DEBUG_LOG(VERBOSE, "uncached adap %d, control %d\n", | ||
241 | phm->adapter_index, *pw_control_index); | ||
242 | return 0; | ||
243 | } else { | ||
244 | HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", | ||
245 | (*pI)->control_type); | ||
246 | } | ||
247 | return 1; | ||
248 | } | ||
249 | |||
250 | /** Used by the kernel driver to figure out if a buffer needs mapping. | ||
251 | */ | ||
252 | short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache, | ||
253 | struct hpi_message *phm, void **p, unsigned int *pN) | ||
254 | { | ||
255 | *pN = 0; | ||
256 | *p = NULL; | ||
257 | if ((phm->function == HPI_CONTROL_GET_STATE) | ||
258 | && (phm->object == HPI_OBJ_CONTROLEX) | ||
259 | ) { | ||
260 | u16 control_index; | ||
261 | struct hpi_control_cache_info *pI; | ||
262 | |||
263 | if (!find_control(phm, p_cache, &pI, &control_index)) | ||
264 | return 0; | ||
265 | } | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | /* allow unified treatment of several string fields within struct */ | ||
270 | #define HPICMN_PAD_OFS_AND_SIZE(m) {\ | ||
271 | offsetof(struct hpi_control_cache_pad, m), \ | ||
272 | sizeof(((struct hpi_control_cache_pad *)(NULL))->m) } | ||
273 | |||
274 | struct pad_ofs_size { | ||
275 | unsigned int offset; | ||
276 | unsigned int field_size; | ||
277 | }; | ||
278 | |||
279 | static struct pad_ofs_size pad_desc[] = { | ||
280 | HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ | ||
281 | HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ | ||
282 | HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ | ||
283 | HPICMN_PAD_OFS_AND_SIZE(c_comment), /* HPI_PAD_COMMENT */ | ||
284 | }; | ||
285 | |||
286 | /** CheckControlCache checks the cache and fills the struct hpi_response | ||
287 | * accordingly. It returns one if a cache hit occurred, zero otherwise. | ||
288 | */ | ||
289 | short hpi_check_control_cache(struct hpi_control_cache *p_cache, | ||
290 | struct hpi_message *phm, struct hpi_response *phr) | ||
291 | { | ||
292 | short found = 1; | ||
293 | u16 control_index; | ||
294 | struct hpi_control_cache_info *pI; | ||
295 | struct hpi_control_cache_single *pC; | ||
296 | struct hpi_control_cache_pad *p_pad; | ||
297 | |||
298 | if (!find_control(phm, p_cache, &pI, &control_index)) | ||
299 | return 0; | ||
300 | |||
301 | phr->error = 0; | ||
302 | |||
303 | /* pC is the default cached control strucure. May be cast to | ||
304 | something else in the following switch statement. | ||
305 | */ | ||
306 | pC = (struct hpi_control_cache_single *)pI; | ||
307 | p_pad = (struct hpi_control_cache_pad *)pI; | ||
308 | |||
309 | switch (pI->control_type) { | ||
310 | |||
311 | case HPI_CONTROL_METER: | ||
312 | if (phm->u.c.attribute == HPI_METER_PEAK) { | ||
313 | phr->u.c.an_log_value[0] = pC->u.p.an_log_peak[0]; | ||
314 | phr->u.c.an_log_value[1] = pC->u.p.an_log_peak[1]; | ||
315 | } else if (phm->u.c.attribute == HPI_METER_RMS) { | ||
316 | phr->u.c.an_log_value[0] = pC->u.p.an_logRMS[0]; | ||
317 | phr->u.c.an_log_value[1] = pC->u.p.an_logRMS[1]; | ||
318 | } else | ||
319 | found = 0; | ||
320 | break; | ||
321 | case HPI_CONTROL_VOLUME: | ||
322 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | ||
323 | phr->u.c.an_log_value[0] = pC->u.v.an_log[0]; | ||
324 | phr->u.c.an_log_value[1] = pC->u.v.an_log[1]; | ||
325 | } else | ||
326 | found = 0; | ||
327 | break; | ||
328 | case HPI_CONTROL_MULTIPLEXER: | ||
329 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | ||
330 | phr->u.c.param1 = pC->u.x.source_node_type; | ||
331 | phr->u.c.param2 = pC->u.x.source_node_index; | ||
332 | } else { | ||
333 | found = 0; | ||
334 | } | ||
335 | break; | ||
336 | case HPI_CONTROL_CHANNEL_MODE: | ||
337 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | ||
338 | phr->u.c.param1 = pC->u.m.mode; | ||
339 | else | ||
340 | found = 0; | ||
341 | break; | ||
342 | case HPI_CONTROL_LEVEL: | ||
343 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | ||
344 | phr->u.c.an_log_value[0] = pC->u.l.an_log[0]; | ||
345 | phr->u.c.an_log_value[1] = pC->u.l.an_log[1]; | ||
346 | } else | ||
347 | found = 0; | ||
348 | break; | ||
349 | case HPI_CONTROL_TUNER: | ||
350 | { | ||
351 | struct hpi_control_cache_single *pCT = | ||
352 | (struct hpi_control_cache_single *)pI; | ||
353 | if (phm->u.c.attribute == HPI_TUNER_FREQ) | ||
354 | phr->u.c.param1 = pCT->u.t.freq_ink_hz; | ||
355 | else if (phm->u.c.attribute == HPI_TUNER_BAND) | ||
356 | phr->u.c.param1 = pCT->u.t.band; | ||
357 | else if ((phm->u.c.attribute == HPI_TUNER_LEVEL) | ||
358 | && (phm->u.c.param1 == | ||
359 | HPI_TUNER_LEVEL_AVERAGE)) | ||
360 | phr->u.c.param1 = pCT->u.t.level; | ||
361 | else | ||
362 | found = 0; | ||
363 | } | ||
364 | break; | ||
365 | case HPI_CONTROL_AESEBU_RECEIVER: | ||
366 | if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS) | ||
367 | phr->u.c.param1 = pC->u.aes3rx.error_status; | ||
368 | else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) | ||
369 | phr->u.c.param1 = pC->u.aes3rx.source; | ||
370 | else | ||
371 | found = 0; | ||
372 | break; | ||
373 | case HPI_CONTROL_AESEBU_TRANSMITTER: | ||
374 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) | ||
375 | phr->u.c.param1 = pC->u.aes3tx.format; | ||
376 | else | ||
377 | found = 0; | ||
378 | break; | ||
379 | case HPI_CONTROL_TONEDETECTOR: | ||
380 | if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE) | ||
381 | phr->u.c.param1 = pC->u.tone.state; | ||
382 | else | ||
383 | found = 0; | ||
384 | break; | ||
385 | case HPI_CONTROL_SILENCEDETECTOR: | ||
386 | if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) { | ||
387 | phr->u.c.param1 = pC->u.silence.state; | ||
388 | phr->u.c.param2 = pC->u.silence.count; | ||
389 | } else | ||
390 | found = 0; | ||
391 | break; | ||
392 | case HPI_CONTROL_MICROPHONE: | ||
393 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | ||
394 | phr->u.c.param1 = pC->u.phantom_power.state; | ||
395 | else | ||
396 | found = 0; | ||
397 | break; | ||
398 | case HPI_CONTROL_SAMPLECLOCK: | ||
399 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) | ||
400 | phr->u.c.param1 = pC->u.clk.source; | ||
401 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) { | ||
402 | if (pC->u.clk.source_index == | ||
403 | HPI_ERROR_ILLEGAL_CACHE_VALUE) { | ||
404 | phr->u.c.param1 = 0; | ||
405 | phr->error = HPI_ERROR_INVALID_OPERATION; | ||
406 | } else | ||
407 | phr->u.c.param1 = pC->u.clk.source_index; | ||
408 | } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | ||
409 | phr->u.c.param1 = pC->u.clk.sample_rate; | ||
410 | else | ||
411 | found = 0; | ||
412 | break; | ||
413 | case HPI_CONTROL_PAD: | ||
414 | |||
415 | if (!(p_pad->field_valid_flags & (1 << | ||
416 | HPI_CTL_ATTR_INDEX(phm->u.c. | ||
417 | attribute)))) { | ||
418 | phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID) | ||
423 | phr->u.c.param1 = p_pad->pI; | ||
424 | else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE) | ||
425 | phr->u.c.param1 = p_pad->pTY; | ||
426 | else { | ||
427 | unsigned int index = | ||
428 | HPI_CTL_ATTR_INDEX(phm->u.c.attribute) - 1; | ||
429 | unsigned int offset = phm->u.c.param1; | ||
430 | unsigned int pad_string_len, field_size; | ||
431 | char *pad_string; | ||
432 | unsigned int tocopy; | ||
433 | |||
434 | HPI_DEBUG_LOG(VERBOSE, "PADS HPI_PADS_ %d\n", | ||
435 | phm->u.c.attribute); | ||
436 | |||
437 | if (index > ARRAY_SIZE(pad_desc) - 1) { | ||
438 | phr->error = | ||
439 | HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | pad_string = ((char *)p_pad) + pad_desc[index].offset; | ||
444 | field_size = pad_desc[index].field_size; | ||
445 | /* Ensure null terminator */ | ||
446 | pad_string[field_size - 1] = 0; | ||
447 | |||
448 | pad_string_len = strlen(pad_string) + 1; | ||
449 | |||
450 | if (offset > pad_string_len) { | ||
451 | phr->error = HPI_ERROR_INVALID_CONTROL_VALUE; | ||
452 | break; | ||
453 | } | ||
454 | |||
455 | tocopy = pad_string_len - offset; | ||
456 | if (tocopy > sizeof(phr->u.cu.chars8.sz_data)) | ||
457 | tocopy = sizeof(phr->u.cu.chars8.sz_data); | ||
458 | |||
459 | HPI_DEBUG_LOG(VERBOSE, | ||
460 | "PADS memcpy(%d), offset %d \n", tocopy, | ||
461 | offset); | ||
462 | memcpy(phr->u.cu.chars8.sz_data, &pad_string[offset], | ||
463 | tocopy); | ||
464 | |||
465 | phr->u.cu.chars8.remaining_chars = | ||
466 | pad_string_len - offset - tocopy; | ||
467 | } | ||
468 | break; | ||
469 | default: | ||
470 | found = 0; | ||
471 | break; | ||
472 | } | ||
473 | |||
474 | if (found) | ||
475 | HPI_DEBUG_LOG(VERBOSE, | ||
476 | "cached adap %d, ctl %d, type %d, attr %d\n", | ||
477 | phm->adapter_index, pI->control_index, | ||
478 | pI->control_type, phm->u.c.attribute); | ||
479 | else | ||
480 | HPI_DEBUG_LOG(VERBOSE, | ||
481 | "uncached adap %d, ctl %d, ctl type %d\n", | ||
482 | phm->adapter_index, pI->control_index, | ||
483 | pI->control_type); | ||
484 | |||
485 | if (found) | ||
486 | phr->size = | ||
487 | sizeof(struct hpi_response_header) + | ||
488 | sizeof(struct hpi_control_res); | ||
489 | |||
490 | return found; | ||
491 | } | ||
492 | |||
493 | /** Updates the cache with Set values. | ||
494 | |||
495 | Only update if no error. | ||
496 | Volume and Level return the limited values in the response, so use these | ||
497 | Multiplexer does so use sent values | ||
498 | */ | ||
499 | void hpi_sync_control_cache(struct hpi_control_cache *p_cache, | ||
500 | struct hpi_message *phm, struct hpi_response *phr) | ||
501 | { | ||
502 | u16 control_index; | ||
503 | struct hpi_control_cache_single *pC; | ||
504 | struct hpi_control_cache_info *pI; | ||
505 | |||
506 | if (!find_control(phm, p_cache, &pI, &control_index)) | ||
507 | return; | ||
508 | |||
509 | /* pC is the default cached control strucure. | ||
510 | May be cast to something else in the following switch statement. | ||
511 | */ | ||
512 | pC = (struct hpi_control_cache_single *)pI; | ||
513 | |||
514 | switch (pI->control_type) { | ||
515 | case HPI_CONTROL_VOLUME: | ||
516 | if (phm->u.c.attribute == HPI_VOLUME_GAIN) { | ||
517 | pC->u.v.an_log[0] = phr->u.c.an_log_value[0]; | ||
518 | pC->u.v.an_log[1] = phr->u.c.an_log_value[1]; | ||
519 | } | ||
520 | break; | ||
521 | case HPI_CONTROL_MULTIPLEXER: | ||
522 | /* mux does not return its setting on Set command. */ | ||
523 | if (phr->error) | ||
524 | return; | ||
525 | if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { | ||
526 | pC->u.x.source_node_type = (u16)phm->u.c.param1; | ||
527 | pC->u.x.source_node_index = (u16)phm->u.c.param2; | ||
528 | } | ||
529 | break; | ||
530 | case HPI_CONTROL_CHANNEL_MODE: | ||
531 | /* mode does not return its setting on Set command. */ | ||
532 | if (phr->error) | ||
533 | return; | ||
534 | if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) | ||
535 | pC->u.m.mode = (u16)phm->u.c.param1; | ||
536 | break; | ||
537 | case HPI_CONTROL_LEVEL: | ||
538 | if (phm->u.c.attribute == HPI_LEVEL_GAIN) { | ||
539 | pC->u.v.an_log[0] = phr->u.c.an_log_value[0]; | ||
540 | pC->u.v.an_log[1] = phr->u.c.an_log_value[1]; | ||
541 | } | ||
542 | break; | ||
543 | case HPI_CONTROL_MICROPHONE: | ||
544 | if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) | ||
545 | pC->u.phantom_power.state = (u16)phm->u.c.param1; | ||
546 | break; | ||
547 | case HPI_CONTROL_AESEBU_TRANSMITTER: | ||
548 | if (phr->error) | ||
549 | return; | ||
550 | if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) | ||
551 | pC->u.aes3tx.format = phm->u.c.param1; | ||
552 | break; | ||
553 | case HPI_CONTROL_AESEBU_RECEIVER: | ||
554 | if (phr->error) | ||
555 | return; | ||
556 | if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) | ||
557 | pC->u.aes3rx.source = phm->u.c.param1; | ||
558 | break; | ||
559 | case HPI_CONTROL_SAMPLECLOCK: | ||
560 | if (phr->error) | ||
561 | return; | ||
562 | if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) | ||
563 | pC->u.clk.source = (u16)phm->u.c.param1; | ||
564 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) | ||
565 | pC->u.clk.source_index = (u16)phm->u.c.param1; | ||
566 | else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) | ||
567 | pC->u.clk.sample_rate = phm->u.c.param1; | ||
568 | break; | ||
569 | default: | ||
570 | break; | ||
571 | } | ||
572 | } | ||
573 | |||
574 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 | ||
575 | number_of_controls, const u32 size_in_bytes, | ||
576 | struct hpi_control_cache_info *pDSP_control_buffer) | ||
577 | { | ||
578 | struct hpi_control_cache *p_cache = | ||
579 | kmalloc(sizeof(*p_cache), GFP_KERNEL); | ||
580 | p_cache->cache_size_in_bytes = size_in_bytes; | ||
581 | p_cache->control_count = number_of_controls; | ||
582 | p_cache->p_cache = | ||
583 | (struct hpi_control_cache_single *)pDSP_control_buffer; | ||
584 | p_cache->init = 0; | ||
585 | p_cache->p_info = | ||
586 | kmalloc(sizeof(*p_cache->p_info) * p_cache->control_count, | ||
587 | GFP_KERNEL); | ||
588 | return p_cache; | ||
589 | } | ||
590 | |||
591 | void hpi_free_control_cache(struct hpi_control_cache *p_cache) | ||
592 | { | ||
593 | if ((p_cache->init) && (p_cache->p_info)) { | ||
594 | kfree(p_cache->p_info); | ||
595 | p_cache->p_info = NULL; | ||
596 | p_cache->init = 0; | ||
597 | kfree(p_cache); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) | ||
602 | { | ||
603 | |||
604 | switch (phm->function) { | ||
605 | case HPI_SUBSYS_OPEN: | ||
606 | case HPI_SUBSYS_CLOSE: | ||
607 | case HPI_SUBSYS_DRIVER_UNLOAD: | ||
608 | phr->error = 0; | ||
609 | break; | ||
610 | case HPI_SUBSYS_DRIVER_LOAD: | ||
611 | wipe_adapter_list(); | ||
612 | hpios_alistlock_init(&adapters); | ||
613 | phr->error = 0; | ||
614 | break; | ||
615 | case HPI_SUBSYS_GET_INFO: | ||
616 | subsys_get_adapters(phr); | ||
617 | break; | ||
618 | case HPI_SUBSYS_CREATE_ADAPTER: | ||
619 | case HPI_SUBSYS_DELETE_ADAPTER: | ||
620 | phr->error = 0; | ||
621 | break; | ||
622 | default: | ||
623 | phr->error = HPI_ERROR_INVALID_FUNC; | ||
624 | break; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr) | ||
629 | { | ||
630 | switch (phm->type) { | ||
631 | case HPI_TYPE_MESSAGE: | ||
632 | switch (phm->object) { | ||
633 | case HPI_OBJ_SUBSYSTEM: | ||
634 | subsys_message(phm, phr); | ||
635 | break; | ||
636 | } | ||
637 | break; | ||
638 | |||
639 | default: | ||
640 | phr->error = HPI_ERROR_INVALID_TYPE; | ||
641 | break; | ||
642 | } | ||
643 | } | ||
diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h new file mode 100644 index 00000000000..6229022f56c --- /dev/null +++ b/sound/pci/asihpi/hpicmn.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | */ | ||
20 | |||
21 | struct hpi_adapter_obj { | ||
22 | struct hpi_pci pci; /* PCI info - bus#,dev#,address etc */ | ||
23 | u16 adapter_type; /* ASI6701 etc */ | ||
24 | u16 index; /* */ | ||
25 | u16 open; /* =1 when adapter open */ | ||
26 | u16 mixer_open; | ||
27 | |||
28 | struct hpios_spinlock dsp_lock; | ||
29 | |||
30 | u16 dsp_crashed; | ||
31 | u16 has_control_cache; | ||
32 | void *priv; | ||
33 | }; | ||
34 | |||
35 | struct hpi_control_cache { | ||
36 | u32 init; /**< indicates whether the | ||
37 | structures are initialized */ | ||
38 | u32 control_count; | ||
39 | u32 cache_size_in_bytes; | ||
40 | struct hpi_control_cache_info | ||
41 | **p_info; /**< pointer to allocated memory of | ||
42 | lookup pointers. */ | ||
43 | struct hpi_control_cache_single | ||
44 | *p_cache; /**< pointer to DSP's control cache. */ | ||
45 | }; | ||
46 | |||
47 | struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index); | ||
48 | u16 hpi_add_adapter(struct hpi_adapter_obj *pao); | ||
49 | |||
50 | void hpi_delete_adapter(struct hpi_adapter_obj *pao); | ||
51 | |||
52 | short hpi_check_control_cache(struct hpi_control_cache *pC, | ||
53 | struct hpi_message *phm, struct hpi_response *phr); | ||
54 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 | ||
55 | number_of_controls, const u32 size_in_bytes, | ||
56 | struct hpi_control_cache_info | ||
57 | *pDSP_control_buffer); | ||
58 | void hpi_free_control_cache(struct hpi_control_cache *p_cache); | ||
59 | |||
60 | void hpi_sync_control_cache(struct hpi_control_cache *pC, | ||
61 | struct hpi_message *phm, struct hpi_response *phr); | ||
62 | u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr); | ||
63 | short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache, | ||
64 | struct hpi_message *phm, void **p, unsigned int *pN); | ||
diff --git a/sound/pci/asihpi/hpidebug.c b/sound/pci/asihpi/hpidebug.c new file mode 100644 index 00000000000..4cd85a401b3 --- /dev/null +++ b/sound/pci/asihpi/hpidebug.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /************************************************************************ | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Debug macro translation. | ||
20 | |||
21 | ************************************************************************/ | ||
22 | |||
23 | #include "hpi_internal.h" | ||
24 | #include "hpidebug.h" | ||
25 | |||
26 | /* Debug level; 0 quiet; 1 informative, 2 debug, 3 verbose debug. */ | ||
27 | int hpi_debug_level = HPI_DEBUG_LEVEL_DEFAULT; | ||
28 | |||
29 | void hpi_debug_init(void) | ||
30 | { | ||
31 | printk(KERN_INFO "debug start\n"); | ||
32 | } | ||
33 | |||
34 | int hpi_debug_level_set(int level) | ||
35 | { | ||
36 | int old_level; | ||
37 | |||
38 | old_level = hpi_debug_level; | ||
39 | hpi_debug_level = level; | ||
40 | return old_level; | ||
41 | } | ||
42 | |||
43 | int hpi_debug_level_get(void) | ||
44 | { | ||
45 | return hpi_debug_level; | ||
46 | } | ||
47 | |||
48 | #ifdef HPIOS_DEBUG_PRINT | ||
49 | /* implies OS has no printf-like function */ | ||
50 | #include <stdarg.h> | ||
51 | |||
52 | void hpi_debug_printf(char *fmt, ...) | ||
53 | { | ||
54 | va_list arglist; | ||
55 | char buffer[128]; | ||
56 | |||
57 | va_start(arglist, fmt); | ||
58 | |||
59 | if (buffer[0]) | ||
60 | HPIOS_DEBUG_PRINT(buffer); | ||
61 | va_end(arglist); | ||
62 | } | ||
63 | #endif | ||
64 | |||
65 | struct treenode { | ||
66 | void *array; | ||
67 | unsigned int num_elements; | ||
68 | }; | ||
69 | |||
70 | #define make_treenode_from_array(nodename, array) \ | ||
71 | static void *tmp_strarray_##nodename[] = array; \ | ||
72 | static struct treenode nodename = { \ | ||
73 | &tmp_strarray_##nodename, \ | ||
74 | ARRAY_SIZE(tmp_strarray_##nodename) \ | ||
75 | }; | ||
76 | |||
77 | #define get_treenode_elem(node_ptr, idx, type) \ | ||
78 | (&(*((type *)(node_ptr)->array)[idx])) | ||
79 | |||
80 | make_treenode_from_array(hpi_control_type_strings, HPI_CONTROL_TYPE_STRINGS) | ||
81 | |||
82 | make_treenode_from_array(hpi_subsys_strings, HPI_SUBSYS_STRINGS) | ||
83 | make_treenode_from_array(hpi_adapter_strings, HPI_ADAPTER_STRINGS) | ||
84 | make_treenode_from_array(hpi_istream_strings, HPI_ISTREAM_STRINGS) | ||
85 | make_treenode_from_array(hpi_ostream_strings, HPI_OSTREAM_STRINGS) | ||
86 | make_treenode_from_array(hpi_mixer_strings, HPI_MIXER_STRINGS) | ||
87 | make_treenode_from_array(hpi_node_strings, | ||
88 | { | ||
89 | "NODE is invalid object"}) | ||
90 | |||
91 | make_treenode_from_array(hpi_control_strings, HPI_CONTROL_STRINGS) | ||
92 | make_treenode_from_array(hpi_nvmemory_strings, HPI_OBJ_STRINGS) | ||
93 | make_treenode_from_array(hpi_digitalio_strings, HPI_DIGITALIO_STRINGS) | ||
94 | make_treenode_from_array(hpi_watchdog_strings, HPI_WATCHDOG_STRINGS) | ||
95 | make_treenode_from_array(hpi_clock_strings, HPI_CLOCK_STRINGS) | ||
96 | make_treenode_from_array(hpi_profile_strings, HPI_PROFILE_STRINGS) | ||
97 | make_treenode_from_array(hpi_asyncevent_strings, HPI_ASYNCEVENT_STRINGS) | ||
98 | #define HPI_FUNCTION_STRINGS \ | ||
99 | { \ | ||
100 | &hpi_subsys_strings,\ | ||
101 | &hpi_adapter_strings,\ | ||
102 | &hpi_ostream_strings,\ | ||
103 | &hpi_istream_strings,\ | ||
104 | &hpi_mixer_strings,\ | ||
105 | &hpi_node_strings,\ | ||
106 | &hpi_control_strings,\ | ||
107 | &hpi_nvmemory_strings,\ | ||
108 | &hpi_digitalio_strings,\ | ||
109 | &hpi_watchdog_strings,\ | ||
110 | &hpi_clock_strings,\ | ||
111 | &hpi_profile_strings,\ | ||
112 | &hpi_control_strings, \ | ||
113 | &hpi_asyncevent_strings \ | ||
114 | }; | ||
115 | make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS) | ||
116 | |||
117 | compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match); | ||
118 | |||
119 | static char *hpi_function_string(unsigned int function) | ||
120 | { | ||
121 | unsigned int object; | ||
122 | struct treenode *tmp; | ||
123 | |||
124 | object = function / HPI_OBJ_FUNCTION_SPACING; | ||
125 | function = function - object * HPI_OBJ_FUNCTION_SPACING; | ||
126 | |||
127 | if (object == 0 || object == HPI_OBJ_NODE | ||
128 | || object > hpi_function_strings.num_elements) | ||
129 | return "invalid object"; | ||
130 | |||
131 | tmp = get_treenode_elem(&hpi_function_strings, object - 1, | ||
132 | struct treenode *); | ||
133 | |||
134 | if (function == 0 || function > tmp->num_elements) | ||
135 | return "invalid function"; | ||
136 | |||
137 | return get_treenode_elem(tmp, function - 1, char *); | ||
138 | } | ||
139 | |||
140 | void hpi_debug_message(struct hpi_message *phm, char *sz_fileline) | ||
141 | { | ||
142 | if (phm) { | ||
143 | if ((phm->object <= HPI_OBJ_MAXINDEX) && phm->object) { | ||
144 | u16 index = 0; | ||
145 | u16 attrib = 0; | ||
146 | int is_control = 0; | ||
147 | |||
148 | index = phm->obj_index; | ||
149 | switch (phm->object) { | ||
150 | case HPI_OBJ_ADAPTER: | ||
151 | case HPI_OBJ_PROFILE: | ||
152 | break; | ||
153 | case HPI_OBJ_MIXER: | ||
154 | if (phm->function == | ||
155 | HPI_MIXER_GET_CONTROL_BY_INDEX) | ||
156 | index = phm->u.m.control_index; | ||
157 | break; | ||
158 | case HPI_OBJ_OSTREAM: | ||
159 | case HPI_OBJ_ISTREAM: | ||
160 | break; | ||
161 | |||
162 | case HPI_OBJ_CONTROLEX: | ||
163 | case HPI_OBJ_CONTROL: | ||
164 | if (phm->version == 1) | ||
165 | attrib = HPI_CTL_ATTR(UNIVERSAL, 1); | ||
166 | else | ||
167 | attrib = phm->u.c.attribute; | ||
168 | is_control = 1; | ||
169 | break; | ||
170 | default: | ||
171 | break; | ||
172 | } | ||
173 | |||
174 | if (is_control && (attrib & 0xFF00)) { | ||
175 | int control_type = (attrib & 0xFF00) >> 8; | ||
176 | int attr_index = HPI_CTL_ATTR_INDEX(attrib); | ||
177 | /* note the KERN facility level | ||
178 | is in szFileline already */ | ||
179 | printk("%s adapter %d %s " | ||
180 | "ctrl_index x%04x %s %d\n", | ||
181 | sz_fileline, phm->adapter_index, | ||
182 | hpi_function_string(phm->function), | ||
183 | index, | ||
184 | get_treenode_elem | ||
185 | (&hpi_control_type_strings, | ||
186 | control_type, char *), | ||
187 | attr_index); | ||
188 | |||
189 | } else | ||
190 | printk("%s adapter %d %s " | ||
191 | "idx x%04x attr x%04x \n", | ||
192 | sz_fileline, phm->adapter_index, | ||
193 | hpi_function_string(phm->function), | ||
194 | index, attrib); | ||
195 | } else { | ||
196 | printk("adap=%d, invalid obj=%d, func=0x%x\n", | ||
197 | phm->adapter_index, phm->object, | ||
198 | phm->function); | ||
199 | } | ||
200 | } else | ||
201 | printk(KERN_ERR | ||
202 | "NULL message pointer to hpi_debug_message!\n"); | ||
203 | } | ||
204 | |||
205 | void hpi_debug_data(u16 *pdata, u32 len) | ||
206 | { | ||
207 | u32 i; | ||
208 | int j; | ||
209 | int k; | ||
210 | int lines; | ||
211 | int cols = 8; | ||
212 | |||
213 | lines = (len + cols - 1) / cols; | ||
214 | if (lines > 8) | ||
215 | lines = 8; | ||
216 | |||
217 | for (i = 0, j = 0; j < lines; j++) { | ||
218 | printk(KERN_DEBUG "%p:", (pdata + i)); | ||
219 | |||
220 | for (k = 0; k < cols && i < len; i++, k++) | ||
221 | printk("%s%04x", k == 0 ? "" : " ", pdata[i]); | ||
222 | |||
223 | printk("\n"); | ||
224 | } | ||
225 | } | ||
diff --git a/sound/pci/asihpi/hpidebug.h b/sound/pci/asihpi/hpidebug.h new file mode 100644 index 00000000000..44dccadcc25 --- /dev/null +++ b/sound/pci/asihpi/hpidebug.h | |||
@@ -0,0 +1,385 @@ | |||
1 | /***************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Debug macros. | ||
20 | |||
21 | *****************************************************************************/ | ||
22 | |||
23 | #ifndef _HPIDEBUG_H | ||
24 | #define _HPIDEBUG_H | ||
25 | |||
26 | #include "hpi_internal.h" | ||
27 | |||
28 | /* Define debugging levels. */ | ||
29 | enum { HPI_DEBUG_LEVEL_ERROR = 0, /* always log errors */ | ||
30 | HPI_DEBUG_LEVEL_WARNING = 1, | ||
31 | HPI_DEBUG_LEVEL_NOTICE = 2, | ||
32 | HPI_DEBUG_LEVEL_INFO = 3, | ||
33 | HPI_DEBUG_LEVEL_DEBUG = 4, | ||
34 | HPI_DEBUG_LEVEL_VERBOSE = 5 /* same printk level as DEBUG */ | ||
35 | }; | ||
36 | |||
37 | #define HPI_DEBUG_LEVEL_DEFAULT HPI_DEBUG_LEVEL_NOTICE | ||
38 | |||
39 | /* an OS can define an extra flag string that is appended to | ||
40 | the start of each message, eg see hpios_linux.h */ | ||
41 | |||
42 | #ifdef SOURCEFILE_NAME | ||
43 | #define FILE_LINE SOURCEFILE_NAME ":" __stringify(__LINE__) " " | ||
44 | #else | ||
45 | #define FILE_LINE __FILE__ ":" __stringify(__LINE__) " " | ||
46 | #endif | ||
47 | |||
48 | #if defined(HPI_DEBUG) && defined(_WINDOWS) | ||
49 | #define HPI_DEBUGBREAK() debug_break() | ||
50 | #else | ||
51 | #define HPI_DEBUGBREAK() | ||
52 | #endif | ||
53 | |||
54 | #define HPI_DEBUG_ASSERT(expression) \ | ||
55 | do { \ | ||
56 | if (!(expression)) {\ | ||
57 | printk(KERN_ERR FILE_LINE\ | ||
58 | "ASSERT " __stringify(expression));\ | ||
59 | HPI_DEBUGBREAK();\ | ||
60 | } \ | ||
61 | } while (0) | ||
62 | |||
63 | #define HPI_DEBUG_LOG(level, ...) \ | ||
64 | do { \ | ||
65 | if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \ | ||
66 | printk(HPI_DEBUG_FLAG_##level \ | ||
67 | FILE_LINE __VA_ARGS__); \ | ||
68 | } \ | ||
69 | } while (0) | ||
70 | |||
71 | void hpi_debug_init(void); | ||
72 | int hpi_debug_level_set(int level); | ||
73 | int hpi_debug_level_get(void); | ||
74 | /* needed by Linux driver for dynamic debug level changes */ | ||
75 | extern int hpi_debug_level; | ||
76 | |||
77 | void hpi_debug_message(struct hpi_message *phm, char *sz_fileline); | ||
78 | |||
79 | void hpi_debug_data(u16 *pdata, u32 len); | ||
80 | |||
81 | #define HPI_DEBUG_DATA(pdata, len) \ | ||
82 | do { \ | ||
83 | if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) \ | ||
84 | hpi_debug_data(pdata, len); \ | ||
85 | } while (0) | ||
86 | |||
87 | #define HPI_DEBUG_MESSAGE(level, phm) \ | ||
88 | do { \ | ||
89 | if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \ | ||
90 | hpi_debug_message(phm,HPI_DEBUG_FLAG_##level \ | ||
91 | FILE_LINE __stringify(level));\ | ||
92 | } \ | ||
93 | } while (0) | ||
94 | |||
95 | #define HPI_DEBUG_RESPONSE(phr) \ | ||
96 | do { \ | ||
97 | if ((hpi_debug_level >= HPI_DEBUG_LEVEL_DEBUG) && (phr->error))\ | ||
98 | HPI_DEBUG_LOG(ERROR, \ | ||
99 | "HPI response - error# %d\n", \ | ||
100 | phr->error); \ | ||
101 | else if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) \ | ||
102 | HPI_DEBUG_LOG(VERBOSE, "HPI response OK\n");\ | ||
103 | } while (0) | ||
104 | |||
105 | #ifndef compile_time_assert | ||
106 | #define compile_time_assert(cond, msg) \ | ||
107 | typedef char msg[(cond) ? 1 : -1] | ||
108 | #endif | ||
109 | |||
110 | /* check that size is exactly some number */ | ||
111 | #define function_count_check(sym, size) \ | ||
112 | compile_time_assert((sym##_FUNCTION_COUNT) == (size),\ | ||
113 | strings_match_defs_##sym) | ||
114 | |||
115 | /* These strings should be generated using a macro which defines | ||
116 | the corresponding symbol values. */ | ||
117 | #define HPI_OBJ_STRINGS \ | ||
118 | { \ | ||
119 | "HPI_OBJ_SUBSYSTEM", \ | ||
120 | "HPI_OBJ_ADAPTER", \ | ||
121 | "HPI_OBJ_OSTREAM", \ | ||
122 | "HPI_OBJ_ISTREAM", \ | ||
123 | "HPI_OBJ_MIXER", \ | ||
124 | "HPI_OBJ_NODE", \ | ||
125 | "HPI_OBJ_CONTROL", \ | ||
126 | "HPI_OBJ_NVMEMORY", \ | ||
127 | "HPI_OBJ_DIGITALIO", \ | ||
128 | "HPI_OBJ_WATCHDOG", \ | ||
129 | "HPI_OBJ_CLOCK", \ | ||
130 | "HPI_OBJ_PROFILE", \ | ||
131 | "HPI_OBJ_CONTROLEX" \ | ||
132 | } | ||
133 | |||
134 | #define HPI_SUBSYS_STRINGS \ | ||
135 | { \ | ||
136 | "HPI_SUBSYS_OPEN", \ | ||
137 | "HPI_SUBSYS_GET_VERSION", \ | ||
138 | "HPI_SUBSYS_GET_INFO", \ | ||
139 | "HPI_SUBSYS_FIND_ADAPTERS", \ | ||
140 | "HPI_SUBSYS_CREATE_ADAPTER",\ | ||
141 | "HPI_SUBSYS_CLOSE", \ | ||
142 | "HPI_SUBSYS_DELETE_ADAPTER", \ | ||
143 | "HPI_SUBSYS_DRIVER_LOAD", \ | ||
144 | "HPI_SUBSYS_DRIVER_UNLOAD", \ | ||
145 | "HPI_SUBSYS_READ_PORT_8", \ | ||
146 | "HPI_SUBSYS_WRITE_PORT_8", \ | ||
147 | "HPI_SUBSYS_GET_NUM_ADAPTERS",\ | ||
148 | "HPI_SUBSYS_GET_ADAPTER", \ | ||
149 | "HPI_SUBSYS_SET_NETWORK_INTERFACE"\ | ||
150 | } | ||
151 | function_count_check(HPI_SUBSYS, 14); | ||
152 | |||
153 | #define HPI_ADAPTER_STRINGS \ | ||
154 | { \ | ||
155 | "HPI_ADAPTER_OPEN", \ | ||
156 | "HPI_ADAPTER_CLOSE", \ | ||
157 | "HPI_ADAPTER_GET_INFO", \ | ||
158 | "HPI_ADAPTER_GET_ASSERT", \ | ||
159 | "HPI_ADAPTER_TEST_ASSERT", \ | ||
160 | "HPI_ADAPTER_SET_MODE", \ | ||
161 | "HPI_ADAPTER_GET_MODE", \ | ||
162 | "HPI_ADAPTER_ENABLE_CAPABILITY",\ | ||
163 | "HPI_ADAPTER_SELFTEST", \ | ||
164 | "HPI_ADAPTER_FIND_OBJECT", \ | ||
165 | "HPI_ADAPTER_QUERY_FLASH", \ | ||
166 | "HPI_ADAPTER_START_FLASH", \ | ||
167 | "HPI_ADAPTER_PROGRAM_FLASH", \ | ||
168 | "HPI_ADAPTER_SET_PROPERTY", \ | ||
169 | "HPI_ADAPTER_GET_PROPERTY", \ | ||
170 | "HPI_ADAPTER_ENUM_PROPERTY", \ | ||
171 | "HPI_ADAPTER_MODULE_INFO", \ | ||
172 | "HPI_ADAPTER_DEBUG_READ" \ | ||
173 | } | ||
174 | |||
175 | function_count_check(HPI_ADAPTER, 18); | ||
176 | |||
177 | #define HPI_OSTREAM_STRINGS \ | ||
178 | { \ | ||
179 | "HPI_OSTREAM_OPEN", \ | ||
180 | "HPI_OSTREAM_CLOSE", \ | ||
181 | "HPI_OSTREAM_WRITE", \ | ||
182 | "HPI_OSTREAM_START", \ | ||
183 | "HPI_OSTREAM_STOP", \ | ||
184 | "HPI_OSTREAM_RESET", \ | ||
185 | "HPI_OSTREAM_GET_INFO", \ | ||
186 | "HPI_OSTREAM_QUERY_FORMAT", \ | ||
187 | "HPI_OSTREAM_DATA", \ | ||
188 | "HPI_OSTREAM_SET_VELOCITY", \ | ||
189 | "HPI_OSTREAM_SET_PUNCHINOUT", \ | ||
190 | "HPI_OSTREAM_SINEGEN", \ | ||
191 | "HPI_OSTREAM_ANC_RESET", \ | ||
192 | "HPI_OSTREAM_ANC_GET_INFO", \ | ||
193 | "HPI_OSTREAM_ANC_READ", \ | ||
194 | "HPI_OSTREAM_SET_TIMESCALE",\ | ||
195 | "HPI_OSTREAM_SET_FORMAT", \ | ||
196 | "HPI_OSTREAM_HOSTBUFFER_ALLOC", \ | ||
197 | "HPI_OSTREAM_HOSTBUFFER_FREE", \ | ||
198 | "HPI_OSTREAM_GROUP_ADD",\ | ||
199 | "HPI_OSTREAM_GROUP_GETMAP", \ | ||
200 | "HPI_OSTREAM_GROUP_RESET", \ | ||
201 | "HPI_OSTREAM_HOSTBUFFER_GET_INFO", \ | ||
202 | "HPI_OSTREAM_WAIT_START", \ | ||
203 | } | ||
204 | function_count_check(HPI_OSTREAM, 24); | ||
205 | |||
206 | #define HPI_ISTREAM_STRINGS \ | ||
207 | { \ | ||
208 | "HPI_ISTREAM_OPEN", \ | ||
209 | "HPI_ISTREAM_CLOSE", \ | ||
210 | "HPI_ISTREAM_SET_FORMAT", \ | ||
211 | "HPI_ISTREAM_READ", \ | ||
212 | "HPI_ISTREAM_START", \ | ||
213 | "HPI_ISTREAM_STOP", \ | ||
214 | "HPI_ISTREAM_RESET", \ | ||
215 | "HPI_ISTREAM_GET_INFO", \ | ||
216 | "HPI_ISTREAM_QUERY_FORMAT", \ | ||
217 | "HPI_ISTREAM_ANC_RESET", \ | ||
218 | "HPI_ISTREAM_ANC_GET_INFO", \ | ||
219 | "HPI_ISTREAM_ANC_WRITE", \ | ||
220 | "HPI_ISTREAM_HOSTBUFFER_ALLOC",\ | ||
221 | "HPI_ISTREAM_HOSTBUFFER_FREE", \ | ||
222 | "HPI_ISTREAM_GROUP_ADD", \ | ||
223 | "HPI_ISTREAM_GROUP_GETMAP", \ | ||
224 | "HPI_ISTREAM_GROUP_RESET", \ | ||
225 | "HPI_ISTREAM_HOSTBUFFER_GET_INFO", \ | ||
226 | "HPI_ISTREAM_WAIT_START", \ | ||
227 | } | ||
228 | function_count_check(HPI_ISTREAM, 19); | ||
229 | |||
230 | #define HPI_MIXER_STRINGS \ | ||
231 | { \ | ||
232 | "HPI_MIXER_OPEN", \ | ||
233 | "HPI_MIXER_CLOSE", \ | ||
234 | "HPI_MIXER_GET_INFO", \ | ||
235 | "HPI_MIXER_GET_NODE_INFO", \ | ||
236 | "HPI_MIXER_GET_CONTROL", \ | ||
237 | "HPI_MIXER_SET_CONNECTION", \ | ||
238 | "HPI_MIXER_GET_CONNECTIONS", \ | ||
239 | "HPI_MIXER_GET_CONTROL_BY_INDEX", \ | ||
240 | "HPI_MIXER_GET_CONTROL_ARRAY_BY_INDEX", \ | ||
241 | "HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES", \ | ||
242 | "HPI_MIXER_STORE", \ | ||
243 | } | ||
244 | function_count_check(HPI_MIXER, 11); | ||
245 | |||
246 | #define HPI_CONTROL_STRINGS \ | ||
247 | { \ | ||
248 | "HPI_CONTROL_GET_INFO", \ | ||
249 | "HPI_CONTROL_GET_STATE", \ | ||
250 | "HPI_CONTROL_SET_STATE" \ | ||
251 | } | ||
252 | function_count_check(HPI_CONTROL, 3); | ||
253 | |||
254 | #define HPI_NVMEMORY_STRINGS \ | ||
255 | { \ | ||
256 | "HPI_NVMEMORY_OPEN", \ | ||
257 | "HPI_NVMEMORY_READ_BYTE", \ | ||
258 | "HPI_NVMEMORY_WRITE_BYTE" \ | ||
259 | } | ||
260 | function_count_check(HPI_NVMEMORY, 3); | ||
261 | |||
262 | #define HPI_DIGITALIO_STRINGS \ | ||
263 | { \ | ||
264 | "HPI_GPIO_OPEN", \ | ||
265 | "HPI_GPIO_READ_BIT", \ | ||
266 | "HPI_GPIO_WRITE_BIT", \ | ||
267 | "HPI_GPIO_READ_ALL", \ | ||
268 | "HPI_GPIO_WRITE_STATUS"\ | ||
269 | } | ||
270 | function_count_check(HPI_GPIO, 5); | ||
271 | |||
272 | #define HPI_WATCHDOG_STRINGS \ | ||
273 | { \ | ||
274 | "HPI_WATCHDOG_OPEN", \ | ||
275 | "HPI_WATCHDOG_SET_TIME", \ | ||
276 | "HPI_WATCHDOG_PING" \ | ||
277 | } | ||
278 | |||
279 | #define HPI_CLOCK_STRINGS \ | ||
280 | { \ | ||
281 | "HPI_CLOCK_OPEN", \ | ||
282 | "HPI_CLOCK_SET_TIME", \ | ||
283 | "HPI_CLOCK_GET_TIME" \ | ||
284 | } | ||
285 | |||
286 | #define HPI_PROFILE_STRINGS \ | ||
287 | { \ | ||
288 | "HPI_PROFILE_OPEN_ALL", \ | ||
289 | "HPI_PROFILE_START_ALL", \ | ||
290 | "HPI_PROFILE_STOP_ALL", \ | ||
291 | "HPI_PROFILE_GET", \ | ||
292 | "HPI_PROFILE_GET_IDLECOUNT", \ | ||
293 | "HPI_PROFILE_GET_NAME", \ | ||
294 | "HPI_PROFILE_GET_UTILIZATION" \ | ||
295 | } | ||
296 | function_count_check(HPI_PROFILE, 7); | ||
297 | |||
298 | #define HPI_ASYNCEVENT_STRINGS \ | ||
299 | { \ | ||
300 | "HPI_ASYNCEVENT_OPEN",\ | ||
301 | "HPI_ASYNCEVENT_CLOSE ",\ | ||
302 | "HPI_ASYNCEVENT_WAIT",\ | ||
303 | "HPI_ASYNCEVENT_GETCOUNT",\ | ||
304 | "HPI_ASYNCEVENT_GET",\ | ||
305 | "HPI_ASYNCEVENT_SENDEVENTS"\ | ||
306 | } | ||
307 | function_count_check(HPI_ASYNCEVENT, 6); | ||
308 | |||
309 | #define HPI_CONTROL_TYPE_STRINGS \ | ||
310 | { \ | ||
311 | "null control", \ | ||
312 | "HPI_CONTROL_CONNECTION", \ | ||
313 | "HPI_CONTROL_VOLUME", \ | ||
314 | "HPI_CONTROL_METER", \ | ||
315 | "HPI_CONTROL_MUTE", \ | ||
316 | "HPI_CONTROL_MULTIPLEXER", \ | ||
317 | "HPI_CONTROL_AESEBU_TRANSMITTER", \ | ||
318 | "HPI_CONTROL_AESEBU_RECEIVER", \ | ||
319 | "HPI_CONTROL_LEVEL", \ | ||
320 | "HPI_CONTROL_TUNER", \ | ||
321 | "HPI_CONTROL_ONOFFSWITCH", \ | ||
322 | "HPI_CONTROL_VOX", \ | ||
323 | "HPI_CONTROL_AES18_TRANSMITTER", \ | ||
324 | "HPI_CONTROL_AES18_RECEIVER", \ | ||
325 | "HPI_CONTROL_AES18_BLOCKGENERATOR", \ | ||
326 | "HPI_CONTROL_CHANNEL_MODE", \ | ||
327 | "HPI_CONTROL_BITSTREAM", \ | ||
328 | "HPI_CONTROL_SAMPLECLOCK", \ | ||
329 | "HPI_CONTROL_MICROPHONE", \ | ||
330 | "HPI_CONTROL_PARAMETRIC_EQ", \ | ||
331 | "HPI_CONTROL_COMPANDER", \ | ||
332 | "HPI_CONTROL_COBRANET", \ | ||
333 | "HPI_CONTROL_TONE_DETECT", \ | ||
334 | "HPI_CONTROL_SILENCE_DETECT", \ | ||
335 | "HPI_CONTROL_PAD", \ | ||
336 | "HPI_CONTROL_SRC" ,\ | ||
337 | "HPI_CONTROL_UNIVERSAL" \ | ||
338 | } | ||
339 | |||
340 | compile_time_assert((HPI_CONTROL_LAST_INDEX + 1 == 27), | ||
341 | controltype_strings_match_defs); | ||
342 | |||
343 | #define HPI_SOURCENODE_STRINGS \ | ||
344 | { \ | ||
345 | "no source", \ | ||
346 | "HPI_SOURCENODE_OSTREAM", \ | ||
347 | "HPI_SOURCENODE_LINEIN", \ | ||
348 | "HPI_SOURCENODE_AESEBU_IN", \ | ||
349 | "HPI_SOURCENODE_TUNER", \ | ||
350 | "HPI_SOURCENODE_RF", \ | ||
351 | "HPI_SOURCENODE_CLOCK_SOURCE", \ | ||
352 | "HPI_SOURCENODE_RAW_BITSTREAM", \ | ||
353 | "HPI_SOURCENODE_MICROPHONE", \ | ||
354 | "HPI_SOURCENODE_COBRANET", \ | ||
355 | "HPI_SOURCENODE_ANALOG", \ | ||
356 | "HPI_SOURCENODE_ADAPTER" \ | ||
357 | } | ||
358 | |||
359 | compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) == | ||
360 | (12), sourcenode_strings_match_defs); | ||
361 | |||
362 | #define HPI_DESTNODE_STRINGS \ | ||
363 | { \ | ||
364 | "no destination", \ | ||
365 | "HPI_DESTNODE_ISTREAM", \ | ||
366 | "HPI_DESTNODE_LINEOUT", \ | ||
367 | "HPI_DESTNODE_AESEBU_OUT", \ | ||
368 | "HPI_DESTNODE_RF", \ | ||
369 | "HPI_DESTNODE_SPEAKER", \ | ||
370 | "HPI_DESTNODE_COBRANET", \ | ||
371 | "HPI_DESTNODE_ANALOG" \ | ||
372 | } | ||
373 | compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_BASE + 1) == (8), | ||
374 | destnode_strings_match_defs); | ||
375 | |||
376 | #define HPI_CONTROL_CHANNEL_MODE_STRINGS \ | ||
377 | { \ | ||
378 | "XXX HPI_CHANNEL_MODE_ERROR XXX", \ | ||
379 | "HPI_CHANNEL_MODE_NORMAL", \ | ||
380 | "HPI_CHANNEL_MODE_SWAP", \ | ||
381 | "HPI_CHANNEL_MODE_LEFT_ONLY", \ | ||
382 | "HPI_CHANNEL_MODE_RIGHT_ONLY" \ | ||
383 | } | ||
384 | |||
385 | #endif /* _HPIDEBUG_H */ | ||
diff --git a/sound/pci/asihpi/hpidspcd.c b/sound/pci/asihpi/hpidspcd.c new file mode 100644 index 00000000000..9b10d9a5c25 --- /dev/null +++ b/sound/pci/asihpi/hpidspcd.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /***********************************************************************/ | ||
2 | /*! | ||
3 | |||
4 | AudioScience HPI driver | ||
5 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of version 2 of the GNU General Public License as | ||
9 | published by the Free Software Foundation; | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | |||
20 | \file | ||
21 | Functions for reading DSP code to load into DSP | ||
22 | |||
23 | (Linux only:) If DSPCODE_FIRMWARE_LOADER is defined, code is read using | ||
24 | hotplug firmware loader from individual dsp code files | ||
25 | |||
26 | If neither of the above is defined, code is read from linked arrays. | ||
27 | DSPCODE_ARRAY is defined. | ||
28 | |||
29 | HPI_INCLUDE_**** must be defined | ||
30 | and the appropriate hzz?????.c or hex?????.c linked in | ||
31 | |||
32 | */ | ||
33 | /***********************************************************************/ | ||
34 | #define SOURCEFILE_NAME "hpidspcd.c" | ||
35 | #include "hpidspcd.h" | ||
36 | #include "hpidebug.h" | ||
37 | |||
38 | /** | ||
39 | Header structure for binary dsp code file (see asidsp.doc) | ||
40 | This structure must match that used in s2bin.c for generation of asidsp.bin | ||
41 | */ | ||
42 | |||
43 | #ifndef DISABLE_PRAGMA_PACK1 | ||
44 | #pragma pack(push, 1) | ||
45 | #endif | ||
46 | |||
47 | struct code_header { | ||
48 | u32 size; | ||
49 | char type[4]; | ||
50 | u32 adapter; | ||
51 | u32 version; | ||
52 | u32 crc; | ||
53 | }; | ||
54 | |||
55 | #ifndef DISABLE_PRAGMA_PACK1 | ||
56 | #pragma pack(pop) | ||
57 | #endif | ||
58 | |||
59 | #define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \ | ||
60 | HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER))) | ||
61 | |||
62 | /***********************************************************************/ | ||
63 | #include "linux/pci.h" | ||
64 | /*-------------------------------------------------------------------*/ | ||
65 | short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code, | ||
66 | u32 *pos_error_code) | ||
67 | { | ||
68 | const struct firmware *ps_firmware = ps_dsp_code->ps_firmware; | ||
69 | struct code_header header; | ||
70 | char fw_name[20]; | ||
71 | int err; | ||
72 | |||
73 | sprintf(fw_name, "asihpi/dsp%04x.bin", adapter); | ||
74 | HPI_DEBUG_LOG(INFO, "requesting firmware for %s\n", fw_name); | ||
75 | |||
76 | err = request_firmware(&ps_firmware, fw_name, | ||
77 | &ps_dsp_code->ps_dev->dev); | ||
78 | if (err != 0) { | ||
79 | HPI_DEBUG_LOG(ERROR, "%d, request_firmware failed for %s\n", | ||
80 | err, fw_name); | ||
81 | goto error1; | ||
82 | } | ||
83 | if (ps_firmware->size < sizeof(header)) { | ||
84 | HPI_DEBUG_LOG(ERROR, "header size too small %s\n", fw_name); | ||
85 | goto error2; | ||
86 | } | ||
87 | memcpy(&header, ps_firmware->data, sizeof(header)); | ||
88 | if (header.adapter != adapter) { | ||
89 | HPI_DEBUG_LOG(ERROR, "adapter type incorrect %4x != %4x\n", | ||
90 | header.adapter, adapter); | ||
91 | goto error2; | ||
92 | } | ||
93 | if (header.size != ps_firmware->size) { | ||
94 | HPI_DEBUG_LOG(ERROR, "code size wrong %d != %ld\n", | ||
95 | header.size, (unsigned long)ps_firmware->size); | ||
96 | goto error2; | ||
97 | } | ||
98 | |||
99 | if (header.version / 10000 != HPI_VER_DECIMAL / 10000) { | ||
100 | HPI_DEBUG_LOG(ERROR, | ||
101 | "firmware major version mismatch " | ||
102 | "DSP image %d != driver %d\n", header.version, | ||
103 | HPI_VER_DECIMAL); | ||
104 | goto error2; | ||
105 | } | ||
106 | |||
107 | if (header.version != HPI_VER_DECIMAL) { | ||
108 | HPI_DEBUG_LOG(WARNING, | ||
109 | "version mismatch DSP image %d != driver %d\n", | ||
110 | header.version, HPI_VER_DECIMAL); | ||
111 | /* goto error2; still allow driver to load */ | ||
112 | } | ||
113 | |||
114 | HPI_DEBUG_LOG(INFO, "dsp code %s opened\n", fw_name); | ||
115 | ps_dsp_code->ps_firmware = ps_firmware; | ||
116 | ps_dsp_code->block_length = header.size / sizeof(u32); | ||
117 | ps_dsp_code->word_count = sizeof(header) / sizeof(u32); | ||
118 | ps_dsp_code->version = header.version; | ||
119 | ps_dsp_code->crc = header.crc; | ||
120 | return 0; | ||
121 | |||
122 | error2: | ||
123 | release_firmware(ps_firmware); | ||
124 | error1: | ||
125 | ps_dsp_code->ps_firmware = NULL; | ||
126 | ps_dsp_code->block_length = 0; | ||
127 | return HPI_ERROR_DSP_FILE_NOT_FOUND; | ||
128 | } | ||
129 | |||
130 | /*-------------------------------------------------------------------*/ | ||
131 | void hpi_dsp_code_close(struct dsp_code *ps_dsp_code) | ||
132 | { | ||
133 | if (ps_dsp_code->ps_firmware != NULL) { | ||
134 | HPI_DEBUG_LOG(DEBUG, "dsp code closed\n"); | ||
135 | release_firmware(ps_dsp_code->ps_firmware); | ||
136 | ps_dsp_code->ps_firmware = NULL; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /*-------------------------------------------------------------------*/ | ||
141 | void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code) | ||
142 | { | ||
143 | /* Go back to start of data, after header */ | ||
144 | ps_dsp_code->word_count = sizeof(struct code_header) / sizeof(u32); | ||
145 | } | ||
146 | |||
147 | /*-------------------------------------------------------------------*/ | ||
148 | short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword) | ||
149 | { | ||
150 | if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length) | ||
151 | return (HPI_ERROR_DSP_FILE_FORMAT); | ||
152 | |||
153 | *pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code-> | ||
154 | word_count]; | ||
155 | ps_dsp_code->word_count++; | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /*-------------------------------------------------------------------*/ | ||
160 | short hpi_dsp_code_read_block(size_t words_requested, | ||
161 | struct dsp_code *ps_dsp_code, u32 **ppblock) | ||
162 | { | ||
163 | if (ps_dsp_code->word_count + words_requested > | ||
164 | ps_dsp_code->block_length) | ||
165 | return HPI_ERROR_DSP_FILE_FORMAT; | ||
166 | |||
167 | *ppblock = | ||
168 | ((u32 *)(ps_dsp_code->ps_firmware->data)) + | ||
169 | ps_dsp_code->word_count; | ||
170 | ps_dsp_code->word_count += words_requested; | ||
171 | return 0; | ||
172 | } | ||
diff --git a/sound/pci/asihpi/hpidspcd.h b/sound/pci/asihpi/hpidspcd.h new file mode 100644 index 00000000000..d7c24039822 --- /dev/null +++ b/sound/pci/asihpi/hpidspcd.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /***********************************************************************/ | ||
2 | /** | ||
3 | |||
4 | AudioScience HPI driver | ||
5 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of version 2 of the GNU General Public License as | ||
9 | published by the Free Software Foundation; | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | |||
20 | \file | ||
21 | Functions for reading DSP code to load into DSP | ||
22 | |||
23 | hpi_dspcode_defines HPI DSP code loading method | ||
24 | Define exactly one of these to select how the DSP code is supplied to | ||
25 | the adapter. | ||
26 | |||
27 | End users writing applications that use the HPI interface do not have to | ||
28 | use any of the below defines; they are only necessary for building drivers | ||
29 | |||
30 | HPI_DSPCODE_FILE: | ||
31 | DSP code is supplied as a file that is opened and read from by the driver. | ||
32 | |||
33 | HPI_DSPCODE_FIRMWARE: | ||
34 | DSP code is read using the hotplug firmware loader module. | ||
35 | Only valid when compiling the HPI kernel driver under Linux. | ||
36 | */ | ||
37 | /***********************************************************************/ | ||
38 | #ifndef _HPIDSPCD_H_ | ||
39 | #define _HPIDSPCD_H_ | ||
40 | |||
41 | #include "hpi_internal.h" | ||
42 | |||
43 | #ifndef DISABLE_PRAGMA_PACK1 | ||
44 | #pragma pack(push, 1) | ||
45 | #endif | ||
46 | |||
47 | /** Descriptor for dspcode from firmware loader */ | ||
48 | struct dsp_code { | ||
49 | /** Firmware descriptor */ | ||
50 | const struct firmware *ps_firmware; | ||
51 | struct pci_dev *ps_dev; | ||
52 | /** Expected number of words in the whole dsp code,INCL header */ | ||
53 | long int block_length; | ||
54 | /** Number of words read so far */ | ||
55 | long int word_count; | ||
56 | /** Version read from dsp code file */ | ||
57 | u32 version; | ||
58 | /** CRC read from dsp code file */ | ||
59 | u32 crc; | ||
60 | }; | ||
61 | |||
62 | #ifndef DISABLE_PRAGMA_PACK1 | ||
63 | #pragma pack(pop) | ||
64 | #endif | ||
65 | |||
66 | /** Prepare *psDspCode to refer to the requuested adapter. | ||
67 | Searches the file, or selects the appropriate linked array | ||
68 | |||
69 | \return 0 for success, or error code if requested code is not available | ||
70 | */ | ||
71 | short hpi_dsp_code_open( | ||
72 | /** Code identifier, usually adapter family */ | ||
73 | u32 adapter, | ||
74 | /** Pointer to DSP code control structure */ | ||
75 | struct dsp_code *ps_dsp_code, | ||
76 | /** Pointer to dword to receive OS specific error code */ | ||
77 | u32 *pos_error_code); | ||
78 | |||
79 | /** Close the DSP code file */ | ||
80 | void hpi_dsp_code_close(struct dsp_code *ps_dsp_code); | ||
81 | |||
82 | /** Rewind to the beginning of the DSP code file (for verify) */ | ||
83 | void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code); | ||
84 | |||
85 | /** Read one word from the dsp code file | ||
86 | \return 0 for success, or error code if eof, or block length exceeded | ||
87 | */ | ||
88 | short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, | ||
89 | /**< DSP code descriptor */ | ||
90 | u32 *pword /**< where to store the read word */ | ||
91 | ); | ||
92 | |||
93 | /** Get a block of dsp code into an internal buffer, and provide a pointer to | ||
94 | that buffer. (If dsp code is already an array in memory, it is referenced, | ||
95 | not copied.) | ||
96 | |||
97 | \return Error if requested number of words are not available | ||
98 | */ | ||
99 | short hpi_dsp_code_read_block(size_t words_requested, | ||
100 | struct dsp_code *ps_dsp_code, | ||
101 | /* Pointer to store (Pointer to code buffer) */ | ||
102 | u32 **ppblock); | ||
103 | |||
104 | #endif | ||
diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c new file mode 100644 index 00000000000..eda26b31232 --- /dev/null +++ b/sound/pci/asihpi/hpifunc.c | |||
@@ -0,0 +1,3864 @@ | |||
1 | |||
2 | #include "hpi_internal.h" | ||
3 | #include "hpimsginit.h" | ||
4 | |||
5 | #include "hpidebug.h" | ||
6 | |||
7 | struct hpi_handle { | ||
8 | unsigned int obj_index:12; | ||
9 | unsigned int obj_type:4; | ||
10 | unsigned int adapter_index:14; | ||
11 | unsigned int spare:1; | ||
12 | unsigned int read_only:1; | ||
13 | }; | ||
14 | |||
15 | union handle_word { | ||
16 | struct hpi_handle h; | ||
17 | u32 w; | ||
18 | }; | ||
19 | |||
20 | u32 hpi_indexes_to_handle(const char c_object, const u16 adapter_index, | ||
21 | const u16 object_index) | ||
22 | { | ||
23 | union handle_word handle; | ||
24 | |||
25 | handle.h.adapter_index = adapter_index; | ||
26 | handle.h.spare = 0; | ||
27 | handle.h.read_only = 0; | ||
28 | handle.h.obj_type = c_object; | ||
29 | handle.h.obj_index = object_index; | ||
30 | return handle.w; | ||
31 | } | ||
32 | |||
33 | void hpi_handle_to_indexes(const u32 handle, u16 *pw_adapter_index, | ||
34 | u16 *pw_object_index) | ||
35 | { | ||
36 | union handle_word uhandle; | ||
37 | uhandle.w = handle; | ||
38 | |||
39 | if (pw_adapter_index) | ||
40 | *pw_adapter_index = (u16)uhandle.h.adapter_index; | ||
41 | if (pw_object_index) | ||
42 | *pw_object_index = (u16)uhandle.h.obj_index; | ||
43 | } | ||
44 | |||
45 | char hpi_handle_object(const u32 handle) | ||
46 | { | ||
47 | union handle_word uhandle; | ||
48 | uhandle.w = handle; | ||
49 | return (char)uhandle.h.obj_type; | ||
50 | } | ||
51 | |||
52 | #define u32TOINDEX(h, i1) \ | ||
53 | do {\ | ||
54 | if (h == 0) \ | ||
55 | return HPI_ERROR_INVALID_OBJ; \ | ||
56 | else \ | ||
57 | hpi_handle_to_indexes(h, i1, NULL); \ | ||
58 | } while (0) | ||
59 | |||
60 | #define u32TOINDEXES(h, i1, i2) \ | ||
61 | do {\ | ||
62 | if (h == 0) \ | ||
63 | return HPI_ERROR_INVALID_OBJ; \ | ||
64 | else \ | ||
65 | hpi_handle_to_indexes(h, i1, i2);\ | ||
66 | } while (0) | ||
67 | |||
68 | void hpi_format_to_msg(struct hpi_msg_format *pMF, | ||
69 | const struct hpi_format *pF) | ||
70 | { | ||
71 | pMF->sample_rate = pF->sample_rate; | ||
72 | pMF->bit_rate = pF->bit_rate; | ||
73 | pMF->attributes = pF->attributes; | ||
74 | pMF->channels = pF->channels; | ||
75 | pMF->format = pF->format; | ||
76 | } | ||
77 | |||
78 | static void hpi_msg_to_format(struct hpi_format *pF, | ||
79 | struct hpi_msg_format *pMF) | ||
80 | { | ||
81 | pF->sample_rate = pMF->sample_rate; | ||
82 | pF->bit_rate = pMF->bit_rate; | ||
83 | pF->attributes = pMF->attributes; | ||
84 | pF->channels = pMF->channels; | ||
85 | pF->format = pMF->format; | ||
86 | pF->mode_legacy = 0; | ||
87 | pF->unused = 0; | ||
88 | } | ||
89 | |||
90 | void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR) | ||
91 | { | ||
92 | pSR->u.legacy_stream_info.auxiliary_data_available = | ||
93 | pSR->u.stream_info.auxiliary_data_available; | ||
94 | pSR->u.legacy_stream_info.state = pSR->u.stream_info.state; | ||
95 | } | ||
96 | |||
97 | static struct hpi_hsubsys gh_subsys; | ||
98 | |||
99 | struct hpi_hsubsys *hpi_subsys_create(void | ||
100 | ) | ||
101 | { | ||
102 | struct hpi_message hm; | ||
103 | struct hpi_response hr; | ||
104 | |||
105 | memset(&gh_subsys, 0, sizeof(struct hpi_hsubsys)); | ||
106 | |||
107 | { | ||
108 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
109 | HPI_SUBSYS_OPEN); | ||
110 | hpi_send_recv(&hm, &hr); | ||
111 | |||
112 | if (hr.error == 0) | ||
113 | return &gh_subsys; | ||
114 | |||
115 | } | ||
116 | return NULL; | ||
117 | } | ||
118 | |||
119 | void hpi_subsys_free(const struct hpi_hsubsys *ph_subsys) | ||
120 | { | ||
121 | struct hpi_message hm; | ||
122 | struct hpi_response hr; | ||
123 | |||
124 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
125 | HPI_SUBSYS_CLOSE); | ||
126 | hpi_send_recv(&hm, &hr); | ||
127 | |||
128 | } | ||
129 | |||
130 | u16 hpi_subsys_get_version(const struct hpi_hsubsys *ph_subsys, u32 *pversion) | ||
131 | { | ||
132 | struct hpi_message hm; | ||
133 | struct hpi_response hr; | ||
134 | |||
135 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
136 | HPI_SUBSYS_GET_VERSION); | ||
137 | hpi_send_recv(&hm, &hr); | ||
138 | *pversion = hr.u.s.version; | ||
139 | return hr.error; | ||
140 | } | ||
141 | |||
142 | u16 hpi_subsys_get_version_ex(const struct hpi_hsubsys *ph_subsys, | ||
143 | u32 *pversion_ex) | ||
144 | { | ||
145 | struct hpi_message hm; | ||
146 | struct hpi_response hr; | ||
147 | |||
148 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
149 | HPI_SUBSYS_GET_VERSION); | ||
150 | hpi_send_recv(&hm, &hr); | ||
151 | *pversion_ex = hr.u.s.data; | ||
152 | return hr.error; | ||
153 | } | ||
154 | |||
155 | u16 hpi_subsys_get_info(const struct hpi_hsubsys *ph_subsys, u32 *pversion, | ||
156 | u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length) | ||
157 | { | ||
158 | struct hpi_message hm; | ||
159 | struct hpi_response hr; | ||
160 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
161 | HPI_SUBSYS_GET_INFO); | ||
162 | |||
163 | hpi_send_recv(&hm, &hr); | ||
164 | |||
165 | *pversion = hr.u.s.version; | ||
166 | if (list_length > HPI_MAX_ADAPTERS) | ||
167 | memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list, | ||
168 | HPI_MAX_ADAPTERS); | ||
169 | else | ||
170 | memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list, list_length); | ||
171 | *pw_num_adapters = hr.u.s.num_adapters; | ||
172 | return hr.error; | ||
173 | } | ||
174 | |||
175 | u16 hpi_subsys_find_adapters(const struct hpi_hsubsys *ph_subsys, | ||
176 | u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length) | ||
177 | { | ||
178 | struct hpi_message hm; | ||
179 | struct hpi_response hr; | ||
180 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
181 | HPI_SUBSYS_FIND_ADAPTERS); | ||
182 | |||
183 | hpi_send_recv(&hm, &hr); | ||
184 | |||
185 | if (list_length > HPI_MAX_ADAPTERS) { | ||
186 | memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list, | ||
187 | HPI_MAX_ADAPTERS * sizeof(u16)); | ||
188 | memset(&aw_adapter_list[HPI_MAX_ADAPTERS], 0, | ||
189 | (list_length - HPI_MAX_ADAPTERS) * sizeof(u16)); | ||
190 | } else | ||
191 | memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list, | ||
192 | list_length * sizeof(u16)); | ||
193 | *pw_num_adapters = hr.u.s.num_adapters; | ||
194 | |||
195 | return hr.error; | ||
196 | } | ||
197 | |||
198 | u16 hpi_subsys_create_adapter(const struct hpi_hsubsys *ph_subsys, | ||
199 | const struct hpi_resource *p_resource, u16 *pw_adapter_index) | ||
200 | { | ||
201 | struct hpi_message hm; | ||
202 | struct hpi_response hr; | ||
203 | |||
204 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
205 | HPI_SUBSYS_CREATE_ADAPTER); | ||
206 | hm.u.s.resource = *p_resource; | ||
207 | |||
208 | hpi_send_recv(&hm, &hr); | ||
209 | |||
210 | *pw_adapter_index = hr.u.s.adapter_index; | ||
211 | return hr.error; | ||
212 | } | ||
213 | |||
214 | u16 hpi_subsys_delete_adapter(const struct hpi_hsubsys *ph_subsys, | ||
215 | u16 adapter_index) | ||
216 | { | ||
217 | struct hpi_message hm; | ||
218 | struct hpi_response hr; | ||
219 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
220 | HPI_SUBSYS_DELETE_ADAPTER); | ||
221 | hm.adapter_index = adapter_index; | ||
222 | hpi_send_recv(&hm, &hr); | ||
223 | return hr.error; | ||
224 | } | ||
225 | |||
226 | u16 hpi_subsys_get_num_adapters(const struct hpi_hsubsys *ph_subsys, | ||
227 | int *pn_num_adapters) | ||
228 | { | ||
229 | struct hpi_message hm; | ||
230 | struct hpi_response hr; | ||
231 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
232 | HPI_SUBSYS_GET_NUM_ADAPTERS); | ||
233 | hpi_send_recv(&hm, &hr); | ||
234 | *pn_num_adapters = (int)hr.u.s.num_adapters; | ||
235 | return hr.error; | ||
236 | } | ||
237 | |||
238 | u16 hpi_subsys_get_adapter(const struct hpi_hsubsys *ph_subsys, int iterator, | ||
239 | u32 *padapter_index, u16 *pw_adapter_type) | ||
240 | { | ||
241 | struct hpi_message hm; | ||
242 | struct hpi_response hr; | ||
243 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
244 | HPI_SUBSYS_GET_ADAPTER); | ||
245 | hm.adapter_index = (u16)iterator; | ||
246 | hpi_send_recv(&hm, &hr); | ||
247 | *padapter_index = (int)hr.u.s.adapter_index; | ||
248 | *pw_adapter_type = hr.u.s.aw_adapter_list[0]; | ||
249 | return hr.error; | ||
250 | } | ||
251 | |||
252 | u16 hpi_subsys_set_host_network_interface(const struct hpi_hsubsys *ph_subsys, | ||
253 | const char *sz_interface) | ||
254 | { | ||
255 | struct hpi_message hm; | ||
256 | struct hpi_response hr; | ||
257 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
258 | HPI_SUBSYS_SET_NETWORK_INTERFACE); | ||
259 | if (sz_interface == NULL) | ||
260 | return HPI_ERROR_INVALID_RESOURCE; | ||
261 | hm.u.s.resource.r.net_if = sz_interface; | ||
262 | hpi_send_recv(&hm, &hr); | ||
263 | return hr.error; | ||
264 | } | ||
265 | |||
266 | u16 hpi_adapter_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index) | ||
267 | { | ||
268 | struct hpi_message hm; | ||
269 | struct hpi_response hr; | ||
270 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
271 | HPI_ADAPTER_OPEN); | ||
272 | hm.adapter_index = adapter_index; | ||
273 | |||
274 | hpi_send_recv(&hm, &hr); | ||
275 | |||
276 | return hr.error; | ||
277 | |||
278 | } | ||
279 | |||
280 | u16 hpi_adapter_close(const struct hpi_hsubsys *ph_subsys, u16 adapter_index) | ||
281 | { | ||
282 | struct hpi_message hm; | ||
283 | struct hpi_response hr; | ||
284 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
285 | HPI_ADAPTER_CLOSE); | ||
286 | hm.adapter_index = adapter_index; | ||
287 | |||
288 | hpi_send_recv(&hm, &hr); | ||
289 | |||
290 | return hr.error; | ||
291 | } | ||
292 | |||
293 | u16 hpi_adapter_set_mode(const struct hpi_hsubsys *ph_subsys, | ||
294 | u16 adapter_index, u32 adapter_mode) | ||
295 | { | ||
296 | return hpi_adapter_set_mode_ex(ph_subsys, adapter_index, adapter_mode, | ||
297 | HPI_ADAPTER_MODE_SET); | ||
298 | } | ||
299 | |||
300 | u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys, | ||
301 | u16 adapter_index, u32 adapter_mode, u16 query_or_set) | ||
302 | { | ||
303 | struct hpi_message hm; | ||
304 | struct hpi_response hr; | ||
305 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
306 | HPI_ADAPTER_SET_MODE); | ||
307 | hm.adapter_index = adapter_index; | ||
308 | hm.u.a.adapter_mode = adapter_mode; | ||
309 | hm.u.a.assert_id = query_or_set; | ||
310 | hpi_send_recv(&hm, &hr); | ||
311 | return hr.error; | ||
312 | } | ||
313 | |||
314 | u16 hpi_adapter_get_mode(const struct hpi_hsubsys *ph_subsys, | ||
315 | u16 adapter_index, u32 *padapter_mode) | ||
316 | { | ||
317 | struct hpi_message hm; | ||
318 | struct hpi_response hr; | ||
319 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
320 | HPI_ADAPTER_GET_MODE); | ||
321 | hm.adapter_index = adapter_index; | ||
322 | hpi_send_recv(&hm, &hr); | ||
323 | if (padapter_mode) | ||
324 | *padapter_mode = hr.u.a.serial_number; | ||
325 | return hr.error; | ||
326 | } | ||
327 | |||
328 | u16 hpi_adapter_get_info(const struct hpi_hsubsys *ph_subsys, | ||
329 | u16 adapter_index, u16 *pw_num_outstreams, u16 *pw_num_instreams, | ||
330 | u16 *pw_version, u32 *pserial_number, u16 *pw_adapter_type) | ||
331 | { | ||
332 | struct hpi_message hm; | ||
333 | struct hpi_response hr; | ||
334 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
335 | HPI_ADAPTER_GET_INFO); | ||
336 | hm.adapter_index = adapter_index; | ||
337 | |||
338 | hpi_send_recv(&hm, &hr); | ||
339 | |||
340 | *pw_adapter_type = hr.u.a.adapter_type; | ||
341 | *pw_num_outstreams = hr.u.a.num_outstreams; | ||
342 | *pw_num_instreams = hr.u.a.num_instreams; | ||
343 | *pw_version = hr.u.a.version; | ||
344 | *pserial_number = hr.u.a.serial_number; | ||
345 | return hr.error; | ||
346 | } | ||
347 | |||
348 | u16 hpi_adapter_get_module_by_index(const struct hpi_hsubsys *ph_subsys, | ||
349 | u16 adapter_index, u16 module_index, u16 *pw_num_outputs, | ||
350 | u16 *pw_num_inputs, u16 *pw_version, u32 *pserial_number, | ||
351 | u16 *pw_module_type, u32 *ph_module) | ||
352 | { | ||
353 | struct hpi_message hm; | ||
354 | struct hpi_response hr; | ||
355 | |||
356 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
357 | HPI_ADAPTER_MODULE_INFO); | ||
358 | hm.adapter_index = adapter_index; | ||
359 | hm.u.ax.module_info.index = module_index; | ||
360 | |||
361 | hpi_send_recv(&hm, &hr); | ||
362 | |||
363 | *pw_module_type = hr.u.a.adapter_type; | ||
364 | *pw_num_outputs = hr.u.a.num_outstreams; | ||
365 | *pw_num_inputs = hr.u.a.num_instreams; | ||
366 | *pw_version = hr.u.a.version; | ||
367 | *pserial_number = hr.u.a.serial_number; | ||
368 | *ph_module = 0; | ||
369 | |||
370 | return hr.error; | ||
371 | } | ||
372 | |||
373 | u16 hpi_adapter_get_assert(const struct hpi_hsubsys *ph_subsys, | ||
374 | u16 adapter_index, u16 *assert_present, char *psz_assert, | ||
375 | u16 *pw_line_number) | ||
376 | { | ||
377 | struct hpi_message hm; | ||
378 | struct hpi_response hr; | ||
379 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
380 | HPI_ADAPTER_GET_ASSERT); | ||
381 | hm.adapter_index = adapter_index; | ||
382 | hpi_send_recv(&hm, &hr); | ||
383 | |||
384 | *assert_present = 0; | ||
385 | |||
386 | if (!hr.error) { | ||
387 | |||
388 | *pw_line_number = (u16)hr.u.a.serial_number; | ||
389 | if (*pw_line_number) { | ||
390 | |||
391 | int i; | ||
392 | char *src = (char *)hr.u.a.sz_adapter_assert; | ||
393 | char *dst = psz_assert; | ||
394 | |||
395 | *assert_present = 1; | ||
396 | |||
397 | for (i = 0; i < HPI_STRING_LEN; i++) { | ||
398 | char c; | ||
399 | c = *src++; | ||
400 | *dst++ = c; | ||
401 | if (c == 0) | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | } | ||
406 | } | ||
407 | return hr.error; | ||
408 | } | ||
409 | |||
410 | u16 hpi_adapter_get_assert_ex(const struct hpi_hsubsys *ph_subsys, | ||
411 | u16 adapter_index, u16 *assert_present, char *psz_assert, | ||
412 | u32 *pline_number, u16 *pw_assert_on_dsp) | ||
413 | { | ||
414 | struct hpi_message hm; | ||
415 | struct hpi_response hr; | ||
416 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
417 | HPI_ADAPTER_GET_ASSERT); | ||
418 | hm.adapter_index = adapter_index; | ||
419 | |||
420 | hpi_send_recv(&hm, &hr); | ||
421 | |||
422 | *assert_present = 0; | ||
423 | |||
424 | if (!hr.error) { | ||
425 | |||
426 | *pline_number = hr.u.a.serial_number; | ||
427 | |||
428 | *assert_present = hr.u.a.adapter_type; | ||
429 | |||
430 | *pw_assert_on_dsp = hr.u.a.adapter_index; | ||
431 | |||
432 | if (!*assert_present && *pline_number) | ||
433 | |||
434 | *assert_present = 1; | ||
435 | |||
436 | if (*assert_present) { | ||
437 | |||
438 | int i; | ||
439 | char *src = (char *)hr.u.a.sz_adapter_assert; | ||
440 | char *dst = psz_assert; | ||
441 | |||
442 | for (i = 0; i < HPI_STRING_LEN; i++) { | ||
443 | char c; | ||
444 | c = *src++; | ||
445 | *dst++ = c; | ||
446 | if (c == 0) | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | } else { | ||
451 | *psz_assert = 0; | ||
452 | } | ||
453 | } | ||
454 | return hr.error; | ||
455 | } | ||
456 | |||
457 | u16 hpi_adapter_test_assert(const struct hpi_hsubsys *ph_subsys, | ||
458 | u16 adapter_index, u16 assert_id) | ||
459 | { | ||
460 | struct hpi_message hm; | ||
461 | struct hpi_response hr; | ||
462 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
463 | HPI_ADAPTER_TEST_ASSERT); | ||
464 | hm.adapter_index = adapter_index; | ||
465 | hm.u.a.assert_id = assert_id; | ||
466 | |||
467 | hpi_send_recv(&hm, &hr); | ||
468 | |||
469 | return hr.error; | ||
470 | } | ||
471 | |||
472 | u16 hpi_adapter_enable_capability(const struct hpi_hsubsys *ph_subsys, | ||
473 | u16 adapter_index, u16 capability, u32 key) | ||
474 | { | ||
475 | struct hpi_message hm; | ||
476 | struct hpi_response hr; | ||
477 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
478 | HPI_ADAPTER_ENABLE_CAPABILITY); | ||
479 | hm.adapter_index = adapter_index; | ||
480 | hm.u.a.assert_id = capability; | ||
481 | hm.u.a.adapter_mode = key; | ||
482 | |||
483 | hpi_send_recv(&hm, &hr); | ||
484 | |||
485 | return hr.error; | ||
486 | } | ||
487 | |||
488 | u16 hpi_adapter_self_test(const struct hpi_hsubsys *ph_subsys, | ||
489 | u16 adapter_index) | ||
490 | { | ||
491 | struct hpi_message hm; | ||
492 | struct hpi_response hr; | ||
493 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
494 | HPI_ADAPTER_SELFTEST); | ||
495 | hm.adapter_index = adapter_index; | ||
496 | hpi_send_recv(&hm, &hr); | ||
497 | return hr.error; | ||
498 | } | ||
499 | |||
500 | u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys, | ||
501 | u16 adapter_index, u32 dsp_address, char *p_buffer, int *count_bytes) | ||
502 | { | ||
503 | struct hpi_message hm; | ||
504 | struct hpi_response hr; | ||
505 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
506 | HPI_ADAPTER_DEBUG_READ); | ||
507 | |||
508 | hr.size = sizeof(hr); | ||
509 | |||
510 | hm.adapter_index = adapter_index; | ||
511 | hm.u.ax.debug_read.dsp_address = dsp_address; | ||
512 | |||
513 | if (*count_bytes > sizeof(hr.u.bytes)) | ||
514 | *count_bytes = sizeof(hr.u.bytes); | ||
515 | |||
516 | hm.u.ax.debug_read.count_bytes = *count_bytes; | ||
517 | |||
518 | hpi_send_recv(&hm, &hr); | ||
519 | |||
520 | if (!hr.error) { | ||
521 | *count_bytes = hr.size - 12; | ||
522 | memcpy(p_buffer, &hr.u.bytes, *count_bytes); | ||
523 | } else | ||
524 | *count_bytes = 0; | ||
525 | return hr.error; | ||
526 | } | ||
527 | |||
528 | u16 hpi_adapter_set_property(const struct hpi_hsubsys *ph_subsys, | ||
529 | u16 adapter_index, u16 property, u16 parameter1, u16 parameter2) | ||
530 | { | ||
531 | struct hpi_message hm; | ||
532 | struct hpi_response hr; | ||
533 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
534 | HPI_ADAPTER_SET_PROPERTY); | ||
535 | hm.adapter_index = adapter_index; | ||
536 | hm.u.ax.property_set.property = property; | ||
537 | hm.u.ax.property_set.parameter1 = parameter1; | ||
538 | hm.u.ax.property_set.parameter2 = parameter2; | ||
539 | |||
540 | hpi_send_recv(&hm, &hr); | ||
541 | |||
542 | return hr.error; | ||
543 | } | ||
544 | |||
545 | u16 hpi_adapter_get_property(const struct hpi_hsubsys *ph_subsys, | ||
546 | u16 adapter_index, u16 property, u16 *pw_parameter1, | ||
547 | u16 *pw_parameter2) | ||
548 | { | ||
549 | struct hpi_message hm; | ||
550 | struct hpi_response hr; | ||
551 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
552 | HPI_ADAPTER_GET_PROPERTY); | ||
553 | hm.adapter_index = adapter_index; | ||
554 | hm.u.ax.property_set.property = property; | ||
555 | |||
556 | hpi_send_recv(&hm, &hr); | ||
557 | if (!hr.error) { | ||
558 | if (pw_parameter1) | ||
559 | *pw_parameter1 = hr.u.ax.property_get.parameter1; | ||
560 | if (pw_parameter2) | ||
561 | *pw_parameter2 = hr.u.ax.property_get.parameter2; | ||
562 | } | ||
563 | |||
564 | return hr.error; | ||
565 | } | ||
566 | |||
567 | u16 hpi_adapter_enumerate_property(const struct hpi_hsubsys *ph_subsys, | ||
568 | u16 adapter_index, u16 index, u16 what_to_enumerate, | ||
569 | u16 property_index, u32 *psetting) | ||
570 | { | ||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format, | ||
575 | u32 sample_rate, u32 bit_rate, u32 attributes) | ||
576 | { | ||
577 | u16 error = 0; | ||
578 | struct hpi_msg_format fmt; | ||
579 | |||
580 | switch (channels) { | ||
581 | case 1: | ||
582 | case 2: | ||
583 | case 4: | ||
584 | case 6: | ||
585 | case 8: | ||
586 | case 16: | ||
587 | break; | ||
588 | default: | ||
589 | error = HPI_ERROR_INVALID_CHANNELS; | ||
590 | return error; | ||
591 | } | ||
592 | fmt.channels = channels; | ||
593 | |||
594 | switch (format) { | ||
595 | case HPI_FORMAT_PCM16_SIGNED: | ||
596 | case HPI_FORMAT_PCM24_SIGNED: | ||
597 | case HPI_FORMAT_PCM32_SIGNED: | ||
598 | case HPI_FORMAT_PCM32_FLOAT: | ||
599 | case HPI_FORMAT_PCM16_BIGENDIAN: | ||
600 | case HPI_FORMAT_PCM8_UNSIGNED: | ||
601 | case HPI_FORMAT_MPEG_L1: | ||
602 | case HPI_FORMAT_MPEG_L2: | ||
603 | case HPI_FORMAT_MPEG_L3: | ||
604 | case HPI_FORMAT_DOLBY_AC2: | ||
605 | case HPI_FORMAT_AA_TAGIT1_HITS: | ||
606 | case HPI_FORMAT_AA_TAGIT1_INSERTS: | ||
607 | case HPI_FORMAT_RAW_BITSTREAM: | ||
608 | case HPI_FORMAT_AA_TAGIT1_HITS_EX1: | ||
609 | case HPI_FORMAT_OEM1: | ||
610 | case HPI_FORMAT_OEM2: | ||
611 | break; | ||
612 | default: | ||
613 | error = HPI_ERROR_INVALID_FORMAT; | ||
614 | return error; | ||
615 | } | ||
616 | fmt.format = format; | ||
617 | |||
618 | if (sample_rate < 8000L) { | ||
619 | error = HPI_ERROR_INCOMPATIBLE_SAMPLERATE; | ||
620 | sample_rate = 8000L; | ||
621 | } | ||
622 | if (sample_rate > 200000L) { | ||
623 | error = HPI_ERROR_INCOMPATIBLE_SAMPLERATE; | ||
624 | sample_rate = 200000L; | ||
625 | } | ||
626 | fmt.sample_rate = sample_rate; | ||
627 | |||
628 | switch (format) { | ||
629 | case HPI_FORMAT_MPEG_L1: | ||
630 | case HPI_FORMAT_MPEG_L2: | ||
631 | case HPI_FORMAT_MPEG_L3: | ||
632 | fmt.bit_rate = bit_rate; | ||
633 | break; | ||
634 | case HPI_FORMAT_PCM16_SIGNED: | ||
635 | case HPI_FORMAT_PCM16_BIGENDIAN: | ||
636 | fmt.bit_rate = channels * sample_rate * 2; | ||
637 | break; | ||
638 | case HPI_FORMAT_PCM32_SIGNED: | ||
639 | case HPI_FORMAT_PCM32_FLOAT: | ||
640 | fmt.bit_rate = channels * sample_rate * 4; | ||
641 | break; | ||
642 | case HPI_FORMAT_PCM8_UNSIGNED: | ||
643 | fmt.bit_rate = channels * sample_rate; | ||
644 | break; | ||
645 | default: | ||
646 | fmt.bit_rate = 0; | ||
647 | } | ||
648 | |||
649 | switch (format) { | ||
650 | case HPI_FORMAT_MPEG_L2: | ||
651 | if ((channels == 1) | ||
652 | && (attributes != HPI_MPEG_MODE_DEFAULT)) { | ||
653 | attributes = HPI_MPEG_MODE_DEFAULT; | ||
654 | error = HPI_ERROR_INVALID_FORMAT; | ||
655 | } else if (attributes > HPI_MPEG_MODE_DUALCHANNEL) { | ||
656 | attributes = HPI_MPEG_MODE_DEFAULT; | ||
657 | error = HPI_ERROR_INVALID_FORMAT; | ||
658 | } | ||
659 | fmt.attributes = attributes; | ||
660 | break; | ||
661 | default: | ||
662 | fmt.attributes = attributes; | ||
663 | } | ||
664 | |||
665 | hpi_msg_to_format(p_format, &fmt); | ||
666 | return error; | ||
667 | } | ||
668 | |||
669 | u16 hpi_stream_estimate_buffer_size(struct hpi_format *p_format, | ||
670 | u32 host_polling_rate_in_milli_seconds, u32 *recommended_buffer_size) | ||
671 | { | ||
672 | |||
673 | u32 bytes_per_second; | ||
674 | u32 size; | ||
675 | u16 channels; | ||
676 | struct hpi_format *pF = p_format; | ||
677 | |||
678 | channels = pF->channels; | ||
679 | |||
680 | switch (pF->format) { | ||
681 | case HPI_FORMAT_PCM16_BIGENDIAN: | ||
682 | case HPI_FORMAT_PCM16_SIGNED: | ||
683 | bytes_per_second = pF->sample_rate * 2L * channels; | ||
684 | break; | ||
685 | case HPI_FORMAT_PCM24_SIGNED: | ||
686 | bytes_per_second = pF->sample_rate * 3L * channels; | ||
687 | break; | ||
688 | case HPI_FORMAT_PCM32_SIGNED: | ||
689 | case HPI_FORMAT_PCM32_FLOAT: | ||
690 | bytes_per_second = pF->sample_rate * 4L * channels; | ||
691 | break; | ||
692 | case HPI_FORMAT_PCM8_UNSIGNED: | ||
693 | bytes_per_second = pF->sample_rate * 1L * channels; | ||
694 | break; | ||
695 | case HPI_FORMAT_MPEG_L1: | ||
696 | case HPI_FORMAT_MPEG_L2: | ||
697 | case HPI_FORMAT_MPEG_L3: | ||
698 | bytes_per_second = pF->bit_rate / 8L; | ||
699 | break; | ||
700 | case HPI_FORMAT_DOLBY_AC2: | ||
701 | |||
702 | bytes_per_second = 256000L / 8L; | ||
703 | break; | ||
704 | default: | ||
705 | return HPI_ERROR_INVALID_FORMAT; | ||
706 | } | ||
707 | size = (bytes_per_second * host_polling_rate_in_milli_seconds * 2) / | ||
708 | 1000L; | ||
709 | |||
710 | *recommended_buffer_size = | ||
711 | roundup_pow_of_two(((size + 4095L) & ~4095L)); | ||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | u16 hpi_outstream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
716 | u16 outstream_index, u32 *ph_outstream) | ||
717 | { | ||
718 | struct hpi_message hm; | ||
719 | struct hpi_response hr; | ||
720 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
721 | HPI_OSTREAM_OPEN); | ||
722 | hm.adapter_index = adapter_index; | ||
723 | hm.obj_index = outstream_index; | ||
724 | |||
725 | hpi_send_recv(&hm, &hr); | ||
726 | |||
727 | if (hr.error == 0) | ||
728 | *ph_outstream = | ||
729 | hpi_indexes_to_handle(HPI_OBJ_OSTREAM, adapter_index, | ||
730 | outstream_index); | ||
731 | else | ||
732 | *ph_outstream = 0; | ||
733 | return hr.error; | ||
734 | } | ||
735 | |||
736 | u16 hpi_outstream_close(const struct hpi_hsubsys *ph_subsys, u32 h_outstream) | ||
737 | { | ||
738 | struct hpi_message hm; | ||
739 | struct hpi_response hr; | ||
740 | |||
741 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
742 | HPI_OSTREAM_HOSTBUFFER_FREE); | ||
743 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
744 | hpi_send_recv(&hm, &hr); | ||
745 | |||
746 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
747 | HPI_OSTREAM_GROUP_RESET); | ||
748 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
749 | hpi_send_recv(&hm, &hr); | ||
750 | |||
751 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
752 | HPI_OSTREAM_CLOSE); | ||
753 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
754 | hpi_send_recv(&hm, &hr); | ||
755 | |||
756 | return hr.error; | ||
757 | } | ||
758 | |||
759 | u16 hpi_outstream_get_info_ex(const struct hpi_hsubsys *ph_subsys, | ||
760 | u32 h_outstream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_to_play, | ||
761 | u32 *psamples_played, u32 *pauxiliary_data_to_play) | ||
762 | { | ||
763 | struct hpi_message hm; | ||
764 | struct hpi_response hr; | ||
765 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
766 | HPI_OSTREAM_GET_INFO); | ||
767 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
768 | |||
769 | hpi_send_recv(&hm, &hr); | ||
770 | |||
771 | if (pw_state) | ||
772 | *pw_state = hr.u.d.u.stream_info.state; | ||
773 | if (pbuffer_size) | ||
774 | *pbuffer_size = hr.u.d.u.stream_info.buffer_size; | ||
775 | if (pdata_to_play) | ||
776 | *pdata_to_play = hr.u.d.u.stream_info.data_available; | ||
777 | if (psamples_played) | ||
778 | *psamples_played = hr.u.d.u.stream_info.samples_transferred; | ||
779 | if (pauxiliary_data_to_play) | ||
780 | *pauxiliary_data_to_play = | ||
781 | hr.u.d.u.stream_info.auxiliary_data_available; | ||
782 | return hr.error; | ||
783 | } | ||
784 | |||
785 | u16 hpi_outstream_write_buf(const struct hpi_hsubsys *ph_subsys, | ||
786 | u32 h_outstream, const u8 *pb_data, u32 bytes_to_write, | ||
787 | const struct hpi_format *p_format) | ||
788 | { | ||
789 | struct hpi_message hm; | ||
790 | struct hpi_response hr; | ||
791 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
792 | HPI_OSTREAM_WRITE); | ||
793 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
794 | hm.u.d.u.data.pb_data = (u8 *)pb_data; | ||
795 | hm.u.d.u.data.data_size = bytes_to_write; | ||
796 | |||
797 | hpi_format_to_msg(&hm.u.d.u.data.format, p_format); | ||
798 | |||
799 | hpi_send_recv(&hm, &hr); | ||
800 | |||
801 | return hr.error; | ||
802 | } | ||
803 | |||
804 | u16 hpi_outstream_start(const struct hpi_hsubsys *ph_subsys, u32 h_outstream) | ||
805 | { | ||
806 | struct hpi_message hm; | ||
807 | struct hpi_response hr; | ||
808 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
809 | HPI_OSTREAM_START); | ||
810 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
811 | |||
812 | hpi_send_recv(&hm, &hr); | ||
813 | |||
814 | return hr.error; | ||
815 | } | ||
816 | |||
817 | u16 hpi_outstream_wait_start(const struct hpi_hsubsys *ph_subsys, | ||
818 | u32 h_outstream) | ||
819 | { | ||
820 | struct hpi_message hm; | ||
821 | struct hpi_response hr; | ||
822 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
823 | HPI_OSTREAM_WAIT_START); | ||
824 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
825 | |||
826 | hpi_send_recv(&hm, &hr); | ||
827 | |||
828 | return hr.error; | ||
829 | } | ||
830 | |||
831 | u16 hpi_outstream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_outstream) | ||
832 | { | ||
833 | struct hpi_message hm; | ||
834 | struct hpi_response hr; | ||
835 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
836 | HPI_OSTREAM_STOP); | ||
837 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
838 | |||
839 | hpi_send_recv(&hm, &hr); | ||
840 | |||
841 | return hr.error; | ||
842 | } | ||
843 | |||
844 | u16 hpi_outstream_sinegen(const struct hpi_hsubsys *ph_subsys, | ||
845 | u32 h_outstream) | ||
846 | { | ||
847 | struct hpi_message hm; | ||
848 | struct hpi_response hr; | ||
849 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
850 | HPI_OSTREAM_SINEGEN); | ||
851 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
852 | |||
853 | hpi_send_recv(&hm, &hr); | ||
854 | |||
855 | return hr.error; | ||
856 | } | ||
857 | |||
858 | u16 hpi_outstream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_outstream) | ||
859 | { | ||
860 | struct hpi_message hm; | ||
861 | struct hpi_response hr; | ||
862 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
863 | HPI_OSTREAM_RESET); | ||
864 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
865 | |||
866 | hpi_send_recv(&hm, &hr); | ||
867 | |||
868 | return hr.error; | ||
869 | } | ||
870 | |||
871 | u16 hpi_outstream_query_format(const struct hpi_hsubsys *ph_subsys, | ||
872 | u32 h_outstream, struct hpi_format *p_format) | ||
873 | { | ||
874 | struct hpi_message hm; | ||
875 | struct hpi_response hr; | ||
876 | |||
877 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
878 | HPI_OSTREAM_QUERY_FORMAT); | ||
879 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
880 | |||
881 | hpi_format_to_msg(&hm.u.d.u.data.format, p_format); | ||
882 | |||
883 | hpi_send_recv(&hm, &hr); | ||
884 | |||
885 | return hr.error; | ||
886 | } | ||
887 | |||
888 | u16 hpi_outstream_set_format(const struct hpi_hsubsys *ph_subsys, | ||
889 | u32 h_outstream, struct hpi_format *p_format) | ||
890 | { | ||
891 | struct hpi_message hm; | ||
892 | struct hpi_response hr; | ||
893 | |||
894 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
895 | HPI_OSTREAM_SET_FORMAT); | ||
896 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
897 | |||
898 | hpi_format_to_msg(&hm.u.d.u.data.format, p_format); | ||
899 | |||
900 | hpi_send_recv(&hm, &hr); | ||
901 | |||
902 | return hr.error; | ||
903 | } | ||
904 | |||
905 | u16 hpi_outstream_set_velocity(const struct hpi_hsubsys *ph_subsys, | ||
906 | u32 h_outstream, short velocity) | ||
907 | { | ||
908 | struct hpi_message hm; | ||
909 | struct hpi_response hr; | ||
910 | |||
911 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
912 | HPI_OSTREAM_SET_VELOCITY); | ||
913 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
914 | hm.u.d.u.velocity = velocity; | ||
915 | |||
916 | hpi_send_recv(&hm, &hr); | ||
917 | |||
918 | return hr.error; | ||
919 | } | ||
920 | |||
921 | u16 hpi_outstream_set_punch_in_out(const struct hpi_hsubsys *ph_subsys, | ||
922 | u32 h_outstream, u32 punch_in_sample, u32 punch_out_sample) | ||
923 | { | ||
924 | struct hpi_message hm; | ||
925 | struct hpi_response hr; | ||
926 | |||
927 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
928 | HPI_OSTREAM_SET_PUNCHINOUT); | ||
929 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
930 | |||
931 | hm.u.d.u.pio.punch_in_sample = punch_in_sample; | ||
932 | hm.u.d.u.pio.punch_out_sample = punch_out_sample; | ||
933 | |||
934 | hpi_send_recv(&hm, &hr); | ||
935 | |||
936 | return hr.error; | ||
937 | } | ||
938 | |||
939 | u16 hpi_outstream_ancillary_reset(const struct hpi_hsubsys *ph_subsys, | ||
940 | u32 h_outstream, u16 mode) | ||
941 | { | ||
942 | struct hpi_message hm; | ||
943 | struct hpi_response hr; | ||
944 | |||
945 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
946 | HPI_OSTREAM_ANC_RESET); | ||
947 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
948 | hm.u.d.u.data.format.channels = mode; | ||
949 | hpi_send_recv(&hm, &hr); | ||
950 | return hr.error; | ||
951 | } | ||
952 | |||
953 | u16 hpi_outstream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys, | ||
954 | u32 h_outstream, u32 *pframes_available) | ||
955 | { | ||
956 | struct hpi_message hm; | ||
957 | struct hpi_response hr; | ||
958 | |||
959 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
960 | HPI_OSTREAM_ANC_GET_INFO); | ||
961 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
962 | hpi_send_recv(&hm, &hr); | ||
963 | if (hr.error == 0) { | ||
964 | if (pframes_available) | ||
965 | *pframes_available = | ||
966 | hr.u.d.u.stream_info.data_available / | ||
967 | sizeof(struct hpi_anc_frame); | ||
968 | } | ||
969 | return hr.error; | ||
970 | } | ||
971 | |||
972 | u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys, | ||
973 | u32 h_outstream, struct hpi_anc_frame *p_anc_frame_buffer, | ||
974 | u32 anc_frame_buffer_size_in_bytes, | ||
975 | u32 number_of_ancillary_frames_to_read) | ||
976 | { | ||
977 | struct hpi_message hm; | ||
978 | struct hpi_response hr; | ||
979 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
980 | HPI_OSTREAM_ANC_READ); | ||
981 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
982 | hm.u.d.u.data.pb_data = (u8 *)p_anc_frame_buffer; | ||
983 | hm.u.d.u.data.data_size = | ||
984 | number_of_ancillary_frames_to_read * | ||
985 | sizeof(struct hpi_anc_frame); | ||
986 | if (hm.u.d.u.data.data_size <= anc_frame_buffer_size_in_bytes) | ||
987 | hpi_send_recv(&hm, &hr); | ||
988 | else | ||
989 | hr.error = HPI_ERROR_INVALID_DATA_TRANSFER; | ||
990 | return hr.error; | ||
991 | } | ||
992 | |||
993 | u16 hpi_outstream_set_time_scale(const struct hpi_hsubsys *ph_subsys, | ||
994 | u32 h_outstream, u32 time_scale) | ||
995 | { | ||
996 | struct hpi_message hm; | ||
997 | struct hpi_response hr; | ||
998 | |||
999 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
1000 | HPI_OSTREAM_SET_TIMESCALE); | ||
1001 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
1002 | |||
1003 | hm.u.d.u.time_scale = time_scale; | ||
1004 | |||
1005 | hpi_send_recv(&hm, &hr); | ||
1006 | |||
1007 | return hr.error; | ||
1008 | } | ||
1009 | |||
1010 | u16 hpi_outstream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys, | ||
1011 | u32 h_outstream, u32 size_in_bytes) | ||
1012 | { | ||
1013 | struct hpi_message hm; | ||
1014 | struct hpi_response hr; | ||
1015 | |||
1016 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
1017 | HPI_OSTREAM_HOSTBUFFER_ALLOC); | ||
1018 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
1019 | hm.u.d.u.data.data_size = size_in_bytes; | ||
1020 | hpi_send_recv(&hm, &hr); | ||
1021 | return hr.error; | ||
1022 | } | ||
1023 | |||
1024 | u16 hpi_outstream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys, | ||
1025 | u32 h_outstream, u8 **pp_buffer, | ||
1026 | struct hpi_hostbuffer_status **pp_status) | ||
1027 | { | ||
1028 | struct hpi_message hm; | ||
1029 | struct hpi_response hr; | ||
1030 | |||
1031 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
1032 | HPI_OSTREAM_HOSTBUFFER_GET_INFO); | ||
1033 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
1034 | hpi_send_recv(&hm, &hr); | ||
1035 | |||
1036 | if (hr.error == 0) { | ||
1037 | if (pp_buffer) | ||
1038 | *pp_buffer = hr.u.d.u.hostbuffer_info.p_buffer; | ||
1039 | if (pp_status) | ||
1040 | *pp_status = hr.u.d.u.hostbuffer_info.p_status; | ||
1041 | } | ||
1042 | return hr.error; | ||
1043 | } | ||
1044 | |||
1045 | u16 hpi_outstream_host_buffer_free(const struct hpi_hsubsys *ph_subsys, | ||
1046 | u32 h_outstream) | ||
1047 | { | ||
1048 | struct hpi_message hm; | ||
1049 | struct hpi_response hr; | ||
1050 | |||
1051 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
1052 | HPI_OSTREAM_HOSTBUFFER_FREE); | ||
1053 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
1054 | hpi_send_recv(&hm, &hr); | ||
1055 | return hr.error; | ||
1056 | } | ||
1057 | |||
1058 | u16 hpi_outstream_group_add(const struct hpi_hsubsys *ph_subsys, | ||
1059 | u32 h_outstream, u32 h_stream) | ||
1060 | { | ||
1061 | struct hpi_message hm; | ||
1062 | struct hpi_response hr; | ||
1063 | u16 adapter; | ||
1064 | char c_obj_type; | ||
1065 | |||
1066 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
1067 | HPI_OSTREAM_GROUP_ADD); | ||
1068 | hr.error = 0; | ||
1069 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
1070 | c_obj_type = hpi_handle_object(h_stream); | ||
1071 | switch (c_obj_type) { | ||
1072 | case HPI_OBJ_OSTREAM: | ||
1073 | hm.u.d.u.stream.object_type = HPI_OBJ_OSTREAM; | ||
1074 | u32TOINDEXES(h_stream, &adapter, | ||
1075 | &hm.u.d.u.stream.stream_index); | ||
1076 | break; | ||
1077 | case HPI_OBJ_ISTREAM: | ||
1078 | hm.u.d.u.stream.object_type = HPI_OBJ_ISTREAM; | ||
1079 | u32TOINDEXES(h_stream, &adapter, | ||
1080 | &hm.u.d.u.stream.stream_index); | ||
1081 | break; | ||
1082 | default: | ||
1083 | return HPI_ERROR_INVALID_STREAM; | ||
1084 | } | ||
1085 | if (adapter != hm.adapter_index) | ||
1086 | return HPI_ERROR_NO_INTERADAPTER_GROUPS; | ||
1087 | |||
1088 | hpi_send_recv(&hm, &hr); | ||
1089 | return hr.error; | ||
1090 | } | ||
1091 | |||
1092 | u16 hpi_outstream_group_get_map(const struct hpi_hsubsys *ph_subsys, | ||
1093 | u32 h_outstream, u32 *poutstream_map, u32 *pinstream_map) | ||
1094 | { | ||
1095 | struct hpi_message hm; | ||
1096 | struct hpi_response hr; | ||
1097 | |||
1098 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
1099 | HPI_OSTREAM_GROUP_GETMAP); | ||
1100 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
1101 | hpi_send_recv(&hm, &hr); | ||
1102 | |||
1103 | if (poutstream_map) | ||
1104 | *poutstream_map = hr.u.d.u.group_info.outstream_group_map; | ||
1105 | if (pinstream_map) | ||
1106 | *pinstream_map = hr.u.d.u.group_info.instream_group_map; | ||
1107 | |||
1108 | return hr.error; | ||
1109 | } | ||
1110 | |||
1111 | u16 hpi_outstream_group_reset(const struct hpi_hsubsys *ph_subsys, | ||
1112 | u32 h_outstream) | ||
1113 | { | ||
1114 | struct hpi_message hm; | ||
1115 | struct hpi_response hr; | ||
1116 | |||
1117 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
1118 | HPI_OSTREAM_GROUP_RESET); | ||
1119 | u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index); | ||
1120 | hpi_send_recv(&hm, &hr); | ||
1121 | return hr.error; | ||
1122 | } | ||
1123 | |||
1124 | u16 hpi_instream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1125 | u16 instream_index, u32 *ph_instream) | ||
1126 | { | ||
1127 | struct hpi_message hm; | ||
1128 | struct hpi_response hr; | ||
1129 | |||
1130 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1131 | HPI_ISTREAM_OPEN); | ||
1132 | hm.adapter_index = adapter_index; | ||
1133 | hm.obj_index = instream_index; | ||
1134 | |||
1135 | hpi_send_recv(&hm, &hr); | ||
1136 | |||
1137 | if (hr.error == 0) | ||
1138 | *ph_instream = | ||
1139 | hpi_indexes_to_handle(HPI_OBJ_ISTREAM, adapter_index, | ||
1140 | instream_index); | ||
1141 | else | ||
1142 | *ph_instream = 0; | ||
1143 | |||
1144 | return hr.error; | ||
1145 | } | ||
1146 | |||
1147 | u16 hpi_instream_close(const struct hpi_hsubsys *ph_subsys, u32 h_instream) | ||
1148 | { | ||
1149 | struct hpi_message hm; | ||
1150 | struct hpi_response hr; | ||
1151 | |||
1152 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1153 | HPI_ISTREAM_HOSTBUFFER_FREE); | ||
1154 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1155 | hpi_send_recv(&hm, &hr); | ||
1156 | |||
1157 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1158 | HPI_ISTREAM_GROUP_RESET); | ||
1159 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1160 | hpi_send_recv(&hm, &hr); | ||
1161 | |||
1162 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1163 | HPI_ISTREAM_CLOSE); | ||
1164 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1165 | hpi_send_recv(&hm, &hr); | ||
1166 | |||
1167 | return hr.error; | ||
1168 | } | ||
1169 | |||
1170 | u16 hpi_instream_query_format(const struct hpi_hsubsys *ph_subsys, | ||
1171 | u32 h_instream, const struct hpi_format *p_format) | ||
1172 | { | ||
1173 | struct hpi_message hm; | ||
1174 | struct hpi_response hr; | ||
1175 | |||
1176 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1177 | HPI_ISTREAM_QUERY_FORMAT); | ||
1178 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1179 | hpi_format_to_msg(&hm.u.d.u.data.format, p_format); | ||
1180 | |||
1181 | hpi_send_recv(&hm, &hr); | ||
1182 | |||
1183 | return hr.error; | ||
1184 | } | ||
1185 | |||
1186 | u16 hpi_instream_set_format(const struct hpi_hsubsys *ph_subsys, | ||
1187 | u32 h_instream, const struct hpi_format *p_format) | ||
1188 | { | ||
1189 | struct hpi_message hm; | ||
1190 | struct hpi_response hr; | ||
1191 | |||
1192 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1193 | HPI_ISTREAM_SET_FORMAT); | ||
1194 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1195 | hpi_format_to_msg(&hm.u.d.u.data.format, p_format); | ||
1196 | |||
1197 | hpi_send_recv(&hm, &hr); | ||
1198 | |||
1199 | return hr.error; | ||
1200 | } | ||
1201 | |||
1202 | u16 hpi_instream_read_buf(const struct hpi_hsubsys *ph_subsys, u32 h_instream, | ||
1203 | u8 *pb_data, u32 bytes_to_read) | ||
1204 | { | ||
1205 | struct hpi_message hm; | ||
1206 | struct hpi_response hr; | ||
1207 | |||
1208 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1209 | HPI_ISTREAM_READ); | ||
1210 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1211 | hm.u.d.u.data.data_size = bytes_to_read; | ||
1212 | hm.u.d.u.data.pb_data = pb_data; | ||
1213 | |||
1214 | hpi_send_recv(&hm, &hr); | ||
1215 | |||
1216 | return hr.error; | ||
1217 | } | ||
1218 | |||
1219 | u16 hpi_instream_start(const struct hpi_hsubsys *ph_subsys, u32 h_instream) | ||
1220 | { | ||
1221 | struct hpi_message hm; | ||
1222 | struct hpi_response hr; | ||
1223 | |||
1224 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1225 | HPI_ISTREAM_START); | ||
1226 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1227 | |||
1228 | hpi_send_recv(&hm, &hr); | ||
1229 | |||
1230 | return hr.error; | ||
1231 | } | ||
1232 | |||
1233 | u16 hpi_instream_wait_start(const struct hpi_hsubsys *ph_subsys, | ||
1234 | u32 h_instream) | ||
1235 | { | ||
1236 | struct hpi_message hm; | ||
1237 | struct hpi_response hr; | ||
1238 | |||
1239 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1240 | HPI_ISTREAM_WAIT_START); | ||
1241 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1242 | |||
1243 | hpi_send_recv(&hm, &hr); | ||
1244 | |||
1245 | return hr.error; | ||
1246 | } | ||
1247 | |||
1248 | u16 hpi_instream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_instream) | ||
1249 | { | ||
1250 | struct hpi_message hm; | ||
1251 | struct hpi_response hr; | ||
1252 | |||
1253 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1254 | HPI_ISTREAM_STOP); | ||
1255 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1256 | |||
1257 | hpi_send_recv(&hm, &hr); | ||
1258 | |||
1259 | return hr.error; | ||
1260 | } | ||
1261 | |||
1262 | u16 hpi_instream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_instream) | ||
1263 | { | ||
1264 | struct hpi_message hm; | ||
1265 | struct hpi_response hr; | ||
1266 | |||
1267 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1268 | HPI_ISTREAM_RESET); | ||
1269 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1270 | |||
1271 | hpi_send_recv(&hm, &hr); | ||
1272 | |||
1273 | return hr.error; | ||
1274 | } | ||
1275 | |||
1276 | u16 hpi_instream_get_info_ex(const struct hpi_hsubsys *ph_subsys, | ||
1277 | u32 h_instream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_recorded, | ||
1278 | u32 *psamples_recorded, u32 *pauxiliary_data_recorded) | ||
1279 | { | ||
1280 | struct hpi_message hm; | ||
1281 | struct hpi_response hr; | ||
1282 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1283 | HPI_ISTREAM_GET_INFO); | ||
1284 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1285 | |||
1286 | hpi_send_recv(&hm, &hr); | ||
1287 | |||
1288 | if (pw_state) | ||
1289 | *pw_state = hr.u.d.u.stream_info.state; | ||
1290 | if (pbuffer_size) | ||
1291 | *pbuffer_size = hr.u.d.u.stream_info.buffer_size; | ||
1292 | if (pdata_recorded) | ||
1293 | *pdata_recorded = hr.u.d.u.stream_info.data_available; | ||
1294 | if (psamples_recorded) | ||
1295 | *psamples_recorded = hr.u.d.u.stream_info.samples_transferred; | ||
1296 | if (pauxiliary_data_recorded) | ||
1297 | *pauxiliary_data_recorded = | ||
1298 | hr.u.d.u.stream_info.auxiliary_data_available; | ||
1299 | return hr.error; | ||
1300 | } | ||
1301 | |||
1302 | u16 hpi_instream_ancillary_reset(const struct hpi_hsubsys *ph_subsys, | ||
1303 | u32 h_instream, u16 bytes_per_frame, u16 mode, u16 alignment, | ||
1304 | u16 idle_bit) | ||
1305 | { | ||
1306 | struct hpi_message hm; | ||
1307 | struct hpi_response hr; | ||
1308 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1309 | HPI_ISTREAM_ANC_RESET); | ||
1310 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1311 | hm.u.d.u.data.format.attributes = bytes_per_frame; | ||
1312 | hm.u.d.u.data.format.format = (mode << 8) | (alignment & 0xff); | ||
1313 | hm.u.d.u.data.format.channels = idle_bit; | ||
1314 | hpi_send_recv(&hm, &hr); | ||
1315 | return hr.error; | ||
1316 | } | ||
1317 | |||
1318 | u16 hpi_instream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys, | ||
1319 | u32 h_instream, u32 *pframe_space) | ||
1320 | { | ||
1321 | struct hpi_message hm; | ||
1322 | struct hpi_response hr; | ||
1323 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1324 | HPI_ISTREAM_ANC_GET_INFO); | ||
1325 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1326 | hpi_send_recv(&hm, &hr); | ||
1327 | if (pframe_space) | ||
1328 | *pframe_space = | ||
1329 | (hr.u.d.u.stream_info.buffer_size - | ||
1330 | hr.u.d.u.stream_info.data_available) / | ||
1331 | sizeof(struct hpi_anc_frame); | ||
1332 | return hr.error; | ||
1333 | } | ||
1334 | |||
1335 | u16 hpi_instream_ancillary_write(const struct hpi_hsubsys *ph_subsys, | ||
1336 | u32 h_instream, const struct hpi_anc_frame *p_anc_frame_buffer, | ||
1337 | u32 anc_frame_buffer_size_in_bytes, | ||
1338 | u32 number_of_ancillary_frames_to_write) | ||
1339 | { | ||
1340 | struct hpi_message hm; | ||
1341 | struct hpi_response hr; | ||
1342 | |||
1343 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1344 | HPI_ISTREAM_ANC_WRITE); | ||
1345 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1346 | hm.u.d.u.data.pb_data = (u8 *)p_anc_frame_buffer; | ||
1347 | hm.u.d.u.data.data_size = | ||
1348 | number_of_ancillary_frames_to_write * | ||
1349 | sizeof(struct hpi_anc_frame); | ||
1350 | if (hm.u.d.u.data.data_size <= anc_frame_buffer_size_in_bytes) | ||
1351 | hpi_send_recv(&hm, &hr); | ||
1352 | else | ||
1353 | hr.error = HPI_ERROR_INVALID_DATA_TRANSFER; | ||
1354 | return hr.error; | ||
1355 | } | ||
1356 | |||
1357 | u16 hpi_instream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys, | ||
1358 | u32 h_instream, u32 size_in_bytes) | ||
1359 | { | ||
1360 | |||
1361 | struct hpi_message hm; | ||
1362 | struct hpi_response hr; | ||
1363 | |||
1364 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1365 | HPI_ISTREAM_HOSTBUFFER_ALLOC); | ||
1366 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1367 | hm.u.d.u.data.data_size = size_in_bytes; | ||
1368 | hpi_send_recv(&hm, &hr); | ||
1369 | return hr.error; | ||
1370 | } | ||
1371 | |||
1372 | u16 hpi_instream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys, | ||
1373 | u32 h_instream, u8 **pp_buffer, | ||
1374 | struct hpi_hostbuffer_status **pp_status) | ||
1375 | { | ||
1376 | struct hpi_message hm; | ||
1377 | struct hpi_response hr; | ||
1378 | |||
1379 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1380 | HPI_ISTREAM_HOSTBUFFER_GET_INFO); | ||
1381 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1382 | hpi_send_recv(&hm, &hr); | ||
1383 | |||
1384 | if (hr.error == 0) { | ||
1385 | if (pp_buffer) | ||
1386 | *pp_buffer = hr.u.d.u.hostbuffer_info.p_buffer; | ||
1387 | if (pp_status) | ||
1388 | *pp_status = hr.u.d.u.hostbuffer_info.p_status; | ||
1389 | } | ||
1390 | return hr.error; | ||
1391 | } | ||
1392 | |||
1393 | u16 hpi_instream_host_buffer_free(const struct hpi_hsubsys *ph_subsys, | ||
1394 | u32 h_instream) | ||
1395 | { | ||
1396 | |||
1397 | struct hpi_message hm; | ||
1398 | struct hpi_response hr; | ||
1399 | |||
1400 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1401 | HPI_ISTREAM_HOSTBUFFER_FREE); | ||
1402 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1403 | hpi_send_recv(&hm, &hr); | ||
1404 | return hr.error; | ||
1405 | } | ||
1406 | |||
1407 | u16 hpi_instream_group_add(const struct hpi_hsubsys *ph_subsys, | ||
1408 | u32 h_instream, u32 h_stream) | ||
1409 | { | ||
1410 | struct hpi_message hm; | ||
1411 | struct hpi_response hr; | ||
1412 | u16 adapter; | ||
1413 | char c_obj_type; | ||
1414 | |||
1415 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1416 | HPI_ISTREAM_GROUP_ADD); | ||
1417 | hr.error = 0; | ||
1418 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1419 | c_obj_type = hpi_handle_object(h_stream); | ||
1420 | |||
1421 | switch (c_obj_type) { | ||
1422 | case HPI_OBJ_OSTREAM: | ||
1423 | hm.u.d.u.stream.object_type = HPI_OBJ_OSTREAM; | ||
1424 | u32TOINDEXES(h_stream, &adapter, | ||
1425 | &hm.u.d.u.stream.stream_index); | ||
1426 | break; | ||
1427 | case HPI_OBJ_ISTREAM: | ||
1428 | hm.u.d.u.stream.object_type = HPI_OBJ_ISTREAM; | ||
1429 | u32TOINDEXES(h_stream, &adapter, | ||
1430 | &hm.u.d.u.stream.stream_index); | ||
1431 | break; | ||
1432 | default: | ||
1433 | return HPI_ERROR_INVALID_STREAM; | ||
1434 | } | ||
1435 | |||
1436 | if (adapter != hm.adapter_index) | ||
1437 | return HPI_ERROR_NO_INTERADAPTER_GROUPS; | ||
1438 | |||
1439 | hpi_send_recv(&hm, &hr); | ||
1440 | return hr.error; | ||
1441 | } | ||
1442 | |||
1443 | u16 hpi_instream_group_get_map(const struct hpi_hsubsys *ph_subsys, | ||
1444 | u32 h_instream, u32 *poutstream_map, u32 *pinstream_map) | ||
1445 | { | ||
1446 | struct hpi_message hm; | ||
1447 | struct hpi_response hr; | ||
1448 | |||
1449 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1450 | HPI_ISTREAM_HOSTBUFFER_FREE); | ||
1451 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1452 | hpi_send_recv(&hm, &hr); | ||
1453 | |||
1454 | if (poutstream_map) | ||
1455 | *poutstream_map = hr.u.d.u.group_info.outstream_group_map; | ||
1456 | if (pinstream_map) | ||
1457 | *pinstream_map = hr.u.d.u.group_info.instream_group_map; | ||
1458 | |||
1459 | return hr.error; | ||
1460 | } | ||
1461 | |||
1462 | u16 hpi_instream_group_reset(const struct hpi_hsubsys *ph_subsys, | ||
1463 | u32 h_instream) | ||
1464 | { | ||
1465 | struct hpi_message hm; | ||
1466 | struct hpi_response hr; | ||
1467 | |||
1468 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
1469 | HPI_ISTREAM_GROUP_RESET); | ||
1470 | u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index); | ||
1471 | hpi_send_recv(&hm, &hr); | ||
1472 | return hr.error; | ||
1473 | } | ||
1474 | |||
1475 | u16 hpi_mixer_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
1476 | u32 *ph_mixer) | ||
1477 | { | ||
1478 | struct hpi_message hm; | ||
1479 | struct hpi_response hr; | ||
1480 | hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_OPEN); | ||
1481 | hm.adapter_index = adapter_index; | ||
1482 | |||
1483 | hpi_send_recv(&hm, &hr); | ||
1484 | |||
1485 | if (hr.error == 0) | ||
1486 | *ph_mixer = | ||
1487 | hpi_indexes_to_handle(HPI_OBJ_MIXER, adapter_index, | ||
1488 | 0); | ||
1489 | else | ||
1490 | *ph_mixer = 0; | ||
1491 | return hr.error; | ||
1492 | } | ||
1493 | |||
1494 | u16 hpi_mixer_close(const struct hpi_hsubsys *ph_subsys, u32 h_mixer) | ||
1495 | { | ||
1496 | struct hpi_message hm; | ||
1497 | struct hpi_response hr; | ||
1498 | hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_CLOSE); | ||
1499 | u32TOINDEX(h_mixer, &hm.adapter_index); | ||
1500 | hpi_send_recv(&hm, &hr); | ||
1501 | return hr.error; | ||
1502 | } | ||
1503 | |||
1504 | u16 hpi_mixer_get_control(const struct hpi_hsubsys *ph_subsys, u32 h_mixer, | ||
1505 | u16 src_node_type, u16 src_node_type_index, u16 dst_node_type, | ||
1506 | u16 dst_node_type_index, u16 control_type, u32 *ph_control) | ||
1507 | { | ||
1508 | struct hpi_message hm; | ||
1509 | struct hpi_response hr; | ||
1510 | hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, | ||
1511 | HPI_MIXER_GET_CONTROL); | ||
1512 | u32TOINDEX(h_mixer, &hm.adapter_index); | ||
1513 | hm.u.m.node_type1 = src_node_type; | ||
1514 | hm.u.m.node_index1 = src_node_type_index; | ||
1515 | hm.u.m.node_type2 = dst_node_type; | ||
1516 | hm.u.m.node_index2 = dst_node_type_index; | ||
1517 | hm.u.m.control_type = control_type; | ||
1518 | |||
1519 | hpi_send_recv(&hm, &hr); | ||
1520 | |||
1521 | if (hr.error == 0) | ||
1522 | *ph_control = | ||
1523 | hpi_indexes_to_handle(HPI_OBJ_CONTROL, | ||
1524 | hm.adapter_index, hr.u.m.control_index); | ||
1525 | else | ||
1526 | *ph_control = 0; | ||
1527 | return hr.error; | ||
1528 | } | ||
1529 | |||
1530 | u16 hpi_mixer_get_control_by_index(const struct hpi_hsubsys *ph_subsys, | ||
1531 | u32 h_mixer, u16 control_index, u16 *pw_src_node_type, | ||
1532 | u16 *pw_src_node_index, u16 *pw_dst_node_type, u16 *pw_dst_node_index, | ||
1533 | u16 *pw_control_type, u32 *ph_control) | ||
1534 | { | ||
1535 | struct hpi_message hm; | ||
1536 | struct hpi_response hr; | ||
1537 | hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, | ||
1538 | HPI_MIXER_GET_CONTROL_BY_INDEX); | ||
1539 | u32TOINDEX(h_mixer, &hm.adapter_index); | ||
1540 | hm.u.m.control_index = control_index; | ||
1541 | hpi_send_recv(&hm, &hr); | ||
1542 | |||
1543 | if (pw_src_node_type) { | ||
1544 | *pw_src_node_type = | ||
1545 | hr.u.m.src_node_type + HPI_SOURCENODE_NONE; | ||
1546 | *pw_src_node_index = hr.u.m.src_node_index; | ||
1547 | *pw_dst_node_type = hr.u.m.dst_node_type + HPI_DESTNODE_NONE; | ||
1548 | *pw_dst_node_index = hr.u.m.dst_node_index; | ||
1549 | } | ||
1550 | if (pw_control_type) | ||
1551 | *pw_control_type = hr.u.m.control_index; | ||
1552 | |||
1553 | if (ph_control) { | ||
1554 | if (hr.error == 0) | ||
1555 | *ph_control = | ||
1556 | hpi_indexes_to_handle(HPI_OBJ_CONTROL, | ||
1557 | hm.adapter_index, control_index); | ||
1558 | else | ||
1559 | *ph_control = 0; | ||
1560 | } | ||
1561 | return hr.error; | ||
1562 | } | ||
1563 | |||
1564 | u16 hpi_mixer_store(const struct hpi_hsubsys *ph_subsys, u32 h_mixer, | ||
1565 | enum HPI_MIXER_STORE_COMMAND command, u16 index) | ||
1566 | { | ||
1567 | struct hpi_message hm; | ||
1568 | struct hpi_response hr; | ||
1569 | hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_STORE); | ||
1570 | u32TOINDEX(h_mixer, &hm.adapter_index); | ||
1571 | hm.u.mx.store.command = command; | ||
1572 | hm.u.mx.store.index = index; | ||
1573 | hpi_send_recv(&hm, &hr); | ||
1574 | return hr.error; | ||
1575 | } | ||
1576 | |||
1577 | static | ||
1578 | u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys, | ||
1579 | const u32 h_control, const u16 attrib, const u32 param1, | ||
1580 | const u32 param2) | ||
1581 | { | ||
1582 | struct hpi_message hm; | ||
1583 | struct hpi_response hr; | ||
1584 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1585 | HPI_CONTROL_SET_STATE); | ||
1586 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1587 | hm.u.c.attribute = attrib; | ||
1588 | hm.u.c.param1 = param1; | ||
1589 | hm.u.c.param2 = param2; | ||
1590 | hpi_send_recv(&hm, &hr); | ||
1591 | return hr.error; | ||
1592 | } | ||
1593 | |||
1594 | static | ||
1595 | u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys, | ||
1596 | const u32 h_control, const u16 attrib, u32 param1, u32 param2, | ||
1597 | u32 *pparam1, u32 *pparam2) | ||
1598 | { | ||
1599 | struct hpi_message hm; | ||
1600 | struct hpi_response hr; | ||
1601 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1602 | HPI_CONTROL_GET_STATE); | ||
1603 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1604 | hm.u.c.attribute = attrib; | ||
1605 | hm.u.c.param1 = param1; | ||
1606 | hm.u.c.param2 = param2; | ||
1607 | hpi_send_recv(&hm, &hr); | ||
1608 | if (pparam1) | ||
1609 | *pparam1 = hr.u.c.param1; | ||
1610 | if (pparam2) | ||
1611 | *pparam2 = hr.u.c.param2; | ||
1612 | |||
1613 | return hr.error; | ||
1614 | } | ||
1615 | |||
1616 | #define hpi_control_param1_get(s, h, a, p1) \ | ||
1617 | hpi_control_param_get(s, h, a, 0, 0, p1, NULL) | ||
1618 | #define hpi_control_param2_get(s, h, a, p1, p2) \ | ||
1619 | hpi_control_param_get(s, h, a, 0, 0, p1, p2) | ||
1620 | #define hpi_control_ex_param1_get(s, h, a, p1) \ | ||
1621 | hpi_control_ex_param_get(s, h, a, 0, 0, p1, NULL) | ||
1622 | #define hpi_control_ex_param2_get(s, h, a, p1, p2) \ | ||
1623 | hpi_control_ex_param_get(s, h, a, 0, 0, p1, p2) | ||
1624 | |||
1625 | static | ||
1626 | u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys, | ||
1627 | const u32 h_control, const u16 attrib, const u32 index, | ||
1628 | const u32 param, u32 *psetting) | ||
1629 | { | ||
1630 | struct hpi_message hm; | ||
1631 | struct hpi_response hr; | ||
1632 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1633 | HPI_CONTROL_GET_INFO); | ||
1634 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1635 | |||
1636 | hm.u.c.attribute = attrib; | ||
1637 | hm.u.c.param1 = index; | ||
1638 | hm.u.c.param2 = param; | ||
1639 | |||
1640 | hpi_send_recv(&hm, &hr); | ||
1641 | *psetting = hr.u.c.param1; | ||
1642 | |||
1643 | return hr.error; | ||
1644 | } | ||
1645 | |||
1646 | static u16 hpi_control_get_string(const struct hpi_hsubsys *ph_subsys, | ||
1647 | const u32 h_control, const u16 attribute, char *psz_string, | ||
1648 | const u32 string_length) | ||
1649 | { | ||
1650 | unsigned int sub_string_index = 0, j = 0; | ||
1651 | char c = 0; | ||
1652 | unsigned int n = 0; | ||
1653 | u16 hE = 0; | ||
1654 | |||
1655 | if ((string_length < 1) || (string_length > 256)) | ||
1656 | return HPI_ERROR_INVALID_CONTROL_VALUE; | ||
1657 | for (sub_string_index = 0; sub_string_index < string_length; | ||
1658 | sub_string_index += 8) { | ||
1659 | struct hpi_message hm; | ||
1660 | struct hpi_response hr; | ||
1661 | |||
1662 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1663 | HPI_CONTROL_GET_STATE); | ||
1664 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1665 | hm.u.c.attribute = attribute; | ||
1666 | hm.u.c.param1 = sub_string_index; | ||
1667 | hm.u.c.param2 = 0; | ||
1668 | hpi_send_recv(&hm, &hr); | ||
1669 | |||
1670 | if (sub_string_index == 0 | ||
1671 | && (hr.u.cu.chars8.remaining_chars + 8) > | ||
1672 | string_length) | ||
1673 | return HPI_ERROR_INVALID_CONTROL_VALUE; | ||
1674 | |||
1675 | if (hr.error) { | ||
1676 | hE = hr.error; | ||
1677 | break; | ||
1678 | } | ||
1679 | for (j = 0; j < 8; j++) { | ||
1680 | c = hr.u.cu.chars8.sz_data[j]; | ||
1681 | psz_string[sub_string_index + j] = c; | ||
1682 | n++; | ||
1683 | if (n >= string_length) { | ||
1684 | psz_string[string_length - 1] = 0; | ||
1685 | hE = HPI_ERROR_INVALID_CONTROL_VALUE; | ||
1686 | break; | ||
1687 | } | ||
1688 | if (c == 0) | ||
1689 | break; | ||
1690 | } | ||
1691 | |||
1692 | if ((hr.u.cu.chars8.remaining_chars == 0) | ||
1693 | && ((sub_string_index + j) < string_length) | ||
1694 | && (c != 0)) { | ||
1695 | c = 0; | ||
1696 | psz_string[sub_string_index + j] = c; | ||
1697 | } | ||
1698 | if (c == 0) | ||
1699 | break; | ||
1700 | } | ||
1701 | return hE; | ||
1702 | } | ||
1703 | |||
1704 | u16 HPI_AESEBU__receiver_query_format(const struct hpi_hsubsys *ph_subsys, | ||
1705 | const u32 h_aes_rx, const u32 index, u16 *pw_format) | ||
1706 | { | ||
1707 | u32 qr; | ||
1708 | u16 err; | ||
1709 | |||
1710 | err = hpi_control_query(ph_subsys, h_aes_rx, HPI_AESEBURX_FORMAT, | ||
1711 | index, 0, &qr); | ||
1712 | *pw_format = (u16)qr; | ||
1713 | return err; | ||
1714 | } | ||
1715 | |||
1716 | u16 HPI_AESEBU__receiver_set_format(const struct hpi_hsubsys *ph_subsys, | ||
1717 | u32 h_control, u16 format) | ||
1718 | { | ||
1719 | return hpi_control_param_set(ph_subsys, h_control, | ||
1720 | HPI_AESEBURX_FORMAT, format, 0); | ||
1721 | } | ||
1722 | |||
1723 | u16 HPI_AESEBU__receiver_get_format(const struct hpi_hsubsys *ph_subsys, | ||
1724 | u32 h_control, u16 *pw_format) | ||
1725 | { | ||
1726 | u16 err; | ||
1727 | u32 param; | ||
1728 | |||
1729 | err = hpi_control_param1_get(ph_subsys, h_control, | ||
1730 | HPI_AESEBURX_FORMAT, ¶m); | ||
1731 | if (!err && pw_format) | ||
1732 | *pw_format = (u16)param; | ||
1733 | |||
1734 | return err; | ||
1735 | } | ||
1736 | |||
1737 | u16 HPI_AESEBU__receiver_get_sample_rate(const struct hpi_hsubsys *ph_subsys, | ||
1738 | u32 h_control, u32 *psample_rate) | ||
1739 | { | ||
1740 | return hpi_control_param1_get(ph_subsys, h_control, | ||
1741 | HPI_AESEBURX_SAMPLERATE, psample_rate); | ||
1742 | } | ||
1743 | |||
1744 | u16 HPI_AESEBU__receiver_get_user_data(const struct hpi_hsubsys *ph_subsys, | ||
1745 | u32 h_control, u16 index, u16 *pw_data) | ||
1746 | { | ||
1747 | struct hpi_message hm; | ||
1748 | struct hpi_response hr; | ||
1749 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1750 | HPI_CONTROL_GET_STATE); | ||
1751 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1752 | hm.u.c.attribute = HPI_AESEBURX_USERDATA; | ||
1753 | hm.u.c.param1 = index; | ||
1754 | |||
1755 | hpi_send_recv(&hm, &hr); | ||
1756 | |||
1757 | if (pw_data) | ||
1758 | *pw_data = (u16)hr.u.c.param2; | ||
1759 | return hr.error; | ||
1760 | } | ||
1761 | |||
1762 | u16 HPI_AESEBU__receiver_get_channel_status(const struct hpi_hsubsys | ||
1763 | *ph_subsys, u32 h_control, u16 index, u16 *pw_data) | ||
1764 | { | ||
1765 | struct hpi_message hm; | ||
1766 | struct hpi_response hr; | ||
1767 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1768 | HPI_CONTROL_GET_STATE); | ||
1769 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1770 | hm.u.c.attribute = HPI_AESEBURX_CHANNELSTATUS; | ||
1771 | hm.u.c.param1 = index; | ||
1772 | |||
1773 | hpi_send_recv(&hm, &hr); | ||
1774 | |||
1775 | if (pw_data) | ||
1776 | *pw_data = (u16)hr.u.c.param2; | ||
1777 | return hr.error; | ||
1778 | } | ||
1779 | |||
1780 | u16 HPI_AESEBU__receiver_get_error_status(const struct hpi_hsubsys *ph_subsys, | ||
1781 | u32 h_control, u16 *pw_error_data) | ||
1782 | { | ||
1783 | u32 error_data = 0; | ||
1784 | u16 error = 0; | ||
1785 | |||
1786 | error = hpi_control_param1_get(ph_subsys, h_control, | ||
1787 | HPI_AESEBURX_ERRORSTATUS, &error_data); | ||
1788 | if (pw_error_data) | ||
1789 | *pw_error_data = (u16)error_data; | ||
1790 | return error; | ||
1791 | } | ||
1792 | |||
1793 | u16 HPI_AESEBU__transmitter_set_sample_rate(const struct hpi_hsubsys | ||
1794 | *ph_subsys, u32 h_control, u32 sample_rate) | ||
1795 | { | ||
1796 | return hpi_control_param_set(ph_subsys, h_control, | ||
1797 | HPI_AESEBUTX_SAMPLERATE, sample_rate, 0); | ||
1798 | } | ||
1799 | |||
1800 | u16 HPI_AESEBU__transmitter_set_user_data(const struct hpi_hsubsys *ph_subsys, | ||
1801 | u32 h_control, u16 index, u16 data) | ||
1802 | { | ||
1803 | return hpi_control_param_set(ph_subsys, h_control, | ||
1804 | HPI_AESEBUTX_USERDATA, index, data); | ||
1805 | } | ||
1806 | |||
1807 | u16 HPI_AESEBU__transmitter_set_channel_status(const struct hpi_hsubsys | ||
1808 | *ph_subsys, u32 h_control, u16 index, u16 data) | ||
1809 | { | ||
1810 | return hpi_control_param_set(ph_subsys, h_control, | ||
1811 | HPI_AESEBUTX_CHANNELSTATUS, index, data); | ||
1812 | } | ||
1813 | |||
1814 | u16 HPI_AESEBU__transmitter_get_channel_status(const struct hpi_hsubsys | ||
1815 | *ph_subsys, u32 h_control, u16 index, u16 *pw_data) | ||
1816 | { | ||
1817 | return HPI_ERROR_INVALID_OPERATION; | ||
1818 | } | ||
1819 | |||
1820 | u16 HPI_AESEBU__transmitter_query_format(const struct hpi_hsubsys *ph_subsys, | ||
1821 | const u32 h_aes_tx, const u32 index, u16 *pw_format) | ||
1822 | { | ||
1823 | u32 qr; | ||
1824 | u16 err; | ||
1825 | |||
1826 | err = hpi_control_query(ph_subsys, h_aes_tx, HPI_AESEBUTX_FORMAT, | ||
1827 | index, 0, &qr); | ||
1828 | *pw_format = (u16)qr; | ||
1829 | return err; | ||
1830 | } | ||
1831 | |||
1832 | u16 HPI_AESEBU__transmitter_set_format(const struct hpi_hsubsys *ph_subsys, | ||
1833 | u32 h_control, u16 output_format) | ||
1834 | { | ||
1835 | return hpi_control_param_set(ph_subsys, h_control, | ||
1836 | HPI_AESEBUTX_FORMAT, output_format, 0); | ||
1837 | } | ||
1838 | |||
1839 | u16 HPI_AESEBU__transmitter_get_format(const struct hpi_hsubsys *ph_subsys, | ||
1840 | u32 h_control, u16 *pw_output_format) | ||
1841 | { | ||
1842 | u16 err; | ||
1843 | u32 param; | ||
1844 | |||
1845 | err = hpi_control_param1_get(ph_subsys, h_control, | ||
1846 | HPI_AESEBUTX_FORMAT, ¶m); | ||
1847 | if (!err && pw_output_format) | ||
1848 | *pw_output_format = (u16)param; | ||
1849 | |||
1850 | return err; | ||
1851 | } | ||
1852 | |||
1853 | u16 hpi_bitstream_set_clock_edge(const struct hpi_hsubsys *ph_subsys, | ||
1854 | u32 h_control, u16 edge_type) | ||
1855 | { | ||
1856 | return hpi_control_param_set(ph_subsys, h_control, | ||
1857 | HPI_BITSTREAM_CLOCK_EDGE, edge_type, 0); | ||
1858 | } | ||
1859 | |||
1860 | u16 hpi_bitstream_set_data_polarity(const struct hpi_hsubsys *ph_subsys, | ||
1861 | u32 h_control, u16 polarity) | ||
1862 | { | ||
1863 | return hpi_control_param_set(ph_subsys, h_control, | ||
1864 | HPI_BITSTREAM_DATA_POLARITY, polarity, 0); | ||
1865 | } | ||
1866 | |||
1867 | u16 hpi_bitstream_get_activity(const struct hpi_hsubsys *ph_subsys, | ||
1868 | u32 h_control, u16 *pw_clk_activity, u16 *pw_data_activity) | ||
1869 | { | ||
1870 | struct hpi_message hm; | ||
1871 | struct hpi_response hr; | ||
1872 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
1873 | HPI_CONTROL_GET_STATE); | ||
1874 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1875 | hm.u.c.attribute = HPI_BITSTREAM_ACTIVITY; | ||
1876 | hpi_send_recv(&hm, &hr); | ||
1877 | if (pw_clk_activity) | ||
1878 | *pw_clk_activity = (u16)hr.u.c.param1; | ||
1879 | if (pw_data_activity) | ||
1880 | *pw_data_activity = (u16)hr.u.c.param2; | ||
1881 | return hr.error; | ||
1882 | } | ||
1883 | |||
1884 | u16 hpi_channel_mode_query_mode(const struct hpi_hsubsys *ph_subsys, | ||
1885 | const u32 h_mode, const u32 index, u16 *pw_mode) | ||
1886 | { | ||
1887 | u32 qr; | ||
1888 | u16 err; | ||
1889 | |||
1890 | err = hpi_control_query(ph_subsys, h_mode, HPI_CHANNEL_MODE_MODE, | ||
1891 | index, 0, &qr); | ||
1892 | *pw_mode = (u16)qr; | ||
1893 | return err; | ||
1894 | } | ||
1895 | |||
1896 | u16 hpi_channel_mode_set(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1897 | u16 mode) | ||
1898 | { | ||
1899 | return hpi_control_param_set(ph_subsys, h_control, | ||
1900 | HPI_CHANNEL_MODE_MODE, mode, 0); | ||
1901 | } | ||
1902 | |||
1903 | u16 hpi_channel_mode_get(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1904 | u16 *mode) | ||
1905 | { | ||
1906 | u32 mode32 = 0; | ||
1907 | u16 error = hpi_control_param1_get(ph_subsys, h_control, | ||
1908 | HPI_CHANNEL_MODE_MODE, &mode32); | ||
1909 | if (mode) | ||
1910 | *mode = (u16)mode32; | ||
1911 | return error; | ||
1912 | } | ||
1913 | |||
1914 | u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1915 | u32 hmi_address, u32 byte_count, u8 *pb_data) | ||
1916 | { | ||
1917 | struct hpi_message hm; | ||
1918 | struct hpi_response hr; | ||
1919 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, | ||
1920 | HPI_CONTROL_SET_STATE); | ||
1921 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1922 | |||
1923 | hm.u.cx.u.cobranet_data.byte_count = byte_count; | ||
1924 | hm.u.cx.u.cobranet_data.hmi_address = hmi_address; | ||
1925 | |||
1926 | if (byte_count <= 8) { | ||
1927 | memcpy(hm.u.cx.u.cobranet_data.data, pb_data, byte_count); | ||
1928 | hm.u.cx.attribute = HPI_COBRANET_SET; | ||
1929 | } else { | ||
1930 | hm.u.cx.u.cobranet_bigdata.pb_data = pb_data; | ||
1931 | hm.u.cx.attribute = HPI_COBRANET_SET_DATA; | ||
1932 | } | ||
1933 | |||
1934 | hpi_send_recv(&hm, &hr); | ||
1935 | |||
1936 | return hr.error; | ||
1937 | } | ||
1938 | |||
1939 | u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
1940 | u32 hmi_address, u32 max_byte_count, u32 *pbyte_count, u8 *pb_data) | ||
1941 | { | ||
1942 | struct hpi_message hm; | ||
1943 | struct hpi_response hr; | ||
1944 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, | ||
1945 | HPI_CONTROL_GET_STATE); | ||
1946 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1947 | |||
1948 | hm.u.cx.u.cobranet_data.byte_count = max_byte_count; | ||
1949 | hm.u.cx.u.cobranet_data.hmi_address = hmi_address; | ||
1950 | |||
1951 | if (max_byte_count <= 8) { | ||
1952 | hm.u.cx.attribute = HPI_COBRANET_GET; | ||
1953 | } else { | ||
1954 | hm.u.cx.u.cobranet_bigdata.pb_data = pb_data; | ||
1955 | hm.u.cx.attribute = HPI_COBRANET_GET_DATA; | ||
1956 | } | ||
1957 | |||
1958 | hpi_send_recv(&hm, &hr); | ||
1959 | if (!hr.error && pb_data) { | ||
1960 | |||
1961 | *pbyte_count = hr.u.cx.u.cobranet_data.byte_count; | ||
1962 | |||
1963 | if (*pbyte_count < max_byte_count) | ||
1964 | max_byte_count = *pbyte_count; | ||
1965 | |||
1966 | if (hm.u.cx.attribute == HPI_COBRANET_GET) { | ||
1967 | memcpy(pb_data, hr.u.cx.u.cobranet_data.data, | ||
1968 | max_byte_count); | ||
1969 | } else { | ||
1970 | |||
1971 | } | ||
1972 | |||
1973 | } | ||
1974 | return hr.error; | ||
1975 | } | ||
1976 | |||
1977 | u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys, | ||
1978 | u32 h_control, u32 *pstatus, u32 *preadable_size, | ||
1979 | u32 *pwriteable_size) | ||
1980 | { | ||
1981 | struct hpi_message hm; | ||
1982 | struct hpi_response hr; | ||
1983 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX, | ||
1984 | HPI_CONTROL_GET_STATE); | ||
1985 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
1986 | |||
1987 | hm.u.cx.attribute = HPI_COBRANET_GET_STATUS; | ||
1988 | |||
1989 | hpi_send_recv(&hm, &hr); | ||
1990 | if (!hr.error) { | ||
1991 | if (pstatus) | ||
1992 | *pstatus = hr.u.cx.u.cobranet_status.status; | ||
1993 | if (preadable_size) | ||
1994 | *preadable_size = | ||
1995 | hr.u.cx.u.cobranet_status.readable_size; | ||
1996 | if (pwriteable_size) | ||
1997 | *pwriteable_size = | ||
1998 | hr.u.cx.u.cobranet_status.writeable_size; | ||
1999 | } | ||
2000 | return hr.error; | ||
2001 | } | ||
2002 | |||
2003 | u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys, | ||
2004 | u32 h_control, u32 *pi_paddress) | ||
2005 | { | ||
2006 | u32 byte_count; | ||
2007 | u32 iP; | ||
2008 | u16 error; | ||
2009 | error = hpi_cobranet_hmi_read(ph_subsys, h_control, | ||
2010 | HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count, | ||
2011 | (u8 *)&iP); | ||
2012 | |||
2013 | *pi_paddress = | ||
2014 | ((iP & 0xff000000) >> 8) | ((iP & 0x00ff0000) << 8) | ((iP & | ||
2015 | 0x0000ff00) >> 8) | ((iP & 0x000000ff) << 8); | ||
2016 | |||
2017 | if (error) | ||
2018 | *pi_paddress = 0; | ||
2019 | |||
2020 | return error; | ||
2021 | |||
2022 | } | ||
2023 | |||
2024 | u16 hpi_cobranet_setI_paddress(const struct hpi_hsubsys *ph_subsys, | ||
2025 | u32 h_control, u32 i_paddress) | ||
2026 | { | ||
2027 | u32 iP; | ||
2028 | u16 error; | ||
2029 | |||
2030 | iP = ((i_paddress & 0xff000000) >> 8) | ((i_paddress & 0x00ff0000) << | ||
2031 | 8) | ((i_paddress & 0x0000ff00) >> 8) | ((i_paddress & | ||
2032 | 0x000000ff) << 8); | ||
2033 | |||
2034 | error = hpi_cobranet_hmi_write(ph_subsys, h_control, | ||
2035 | HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, (u8 *)&iP); | ||
2036 | |||
2037 | return error; | ||
2038 | |||
2039 | } | ||
2040 | |||
2041 | u16 hpi_cobranet_get_staticI_paddress(const struct hpi_hsubsys *ph_subsys, | ||
2042 | u32 h_control, u32 *pi_paddress) | ||
2043 | { | ||
2044 | u32 byte_count; | ||
2045 | u32 iP; | ||
2046 | u16 error; | ||
2047 | error = hpi_cobranet_hmi_read(ph_subsys, h_control, | ||
2048 | HPI_COBRANET_HMI_cobra_ip_mon_staticIP, 4, &byte_count, | ||
2049 | (u8 *)&iP); | ||
2050 | |||
2051 | *pi_paddress = | ||
2052 | ((iP & 0xff000000) >> 8) | ((iP & 0x00ff0000) << 8) | ((iP & | ||
2053 | 0x0000ff00) >> 8) | ((iP & 0x000000ff) << 8); | ||
2054 | |||
2055 | if (error) | ||
2056 | *pi_paddress = 0; | ||
2057 | |||
2058 | return error; | ||
2059 | |||
2060 | } | ||
2061 | |||
2062 | u16 hpi_cobranet_set_staticI_paddress(const struct hpi_hsubsys *ph_subsys, | ||
2063 | u32 h_control, u32 i_paddress) | ||
2064 | { | ||
2065 | u32 iP; | ||
2066 | u16 error; | ||
2067 | |||
2068 | iP = ((i_paddress & 0xff000000) >> 8) | ((i_paddress & 0x00ff0000) << | ||
2069 | 8) | ((i_paddress & 0x0000ff00) >> 8) | ((i_paddress & | ||
2070 | 0x000000ff) << 8); | ||
2071 | |||
2072 | error = hpi_cobranet_hmi_write(ph_subsys, h_control, | ||
2073 | HPI_COBRANET_HMI_cobra_ip_mon_staticIP, 4, (u8 *)&iP); | ||
2074 | |||
2075 | return error; | ||
2076 | |||
2077 | } | ||
2078 | |||
2079 | u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys, | ||
2080 | u32 h_control, u32 *pmAC_MS_bs, u32 *pmAC_LS_bs) | ||
2081 | { | ||
2082 | u32 byte_count; | ||
2083 | u16 error; | ||
2084 | u32 mAC; | ||
2085 | error = hpi_cobranet_hmi_read(ph_subsys, h_control, | ||
2086 | HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count, | ||
2087 | (u8 *)&mAC); | ||
2088 | *pmAC_MS_bs = | ||
2089 | ((mAC & 0xff000000) >> 8) | ((mAC & 0x00ff0000) << 8) | ((mAC | ||
2090 | & 0x0000ff00) >> 8) | ((mAC & 0x000000ff) << 8); | ||
2091 | error += hpi_cobranet_hmi_read(ph_subsys, h_control, | ||
2092 | HPI_COBRANET_HMI_cobra_if_phy_address + 1, 4, &byte_count, | ||
2093 | (u8 *)&mAC); | ||
2094 | *pmAC_LS_bs = | ||
2095 | ((mAC & 0xff000000) >> 8) | ((mAC & 0x00ff0000) << 8) | ((mAC | ||
2096 | & 0x0000ff00) >> 8) | ((mAC & 0x000000ff) << 8); | ||
2097 | |||
2098 | if (error) { | ||
2099 | *pmAC_MS_bs = 0; | ||
2100 | *pmAC_LS_bs = 0; | ||
2101 | } | ||
2102 | |||
2103 | return error; | ||
2104 | } | ||
2105 | |||
2106 | u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2107 | u16 attack, u16 decay, short ratio100, short threshold0_01dB, | ||
2108 | short makeup_gain0_01dB) | ||
2109 | { | ||
2110 | struct hpi_message hm; | ||
2111 | struct hpi_response hr; | ||
2112 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2113 | HPI_CONTROL_SET_STATE); | ||
2114 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2115 | |||
2116 | hm.u.c.param1 = attack + ((u32)ratio100 << 16); | ||
2117 | hm.u.c.param2 = (decay & 0xFFFFL); | ||
2118 | hm.u.c.an_log_value[0] = threshold0_01dB; | ||
2119 | hm.u.c.an_log_value[1] = makeup_gain0_01dB; | ||
2120 | hm.u.c.attribute = HPI_COMPANDER_PARAMS; | ||
2121 | |||
2122 | hpi_send_recv(&hm, &hr); | ||
2123 | |||
2124 | return hr.error; | ||
2125 | } | ||
2126 | |||
2127 | u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2128 | u16 *pw_attack, u16 *pw_decay, short *pw_ratio100, | ||
2129 | short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB) | ||
2130 | { | ||
2131 | struct hpi_message hm; | ||
2132 | struct hpi_response hr; | ||
2133 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2134 | HPI_CONTROL_GET_STATE); | ||
2135 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2136 | hm.u.c.attribute = HPI_COMPANDER_PARAMS; | ||
2137 | |||
2138 | hpi_send_recv(&hm, &hr); | ||
2139 | |||
2140 | if (pw_attack) | ||
2141 | *pw_attack = (short)(hr.u.c.param1 & 0xFFFF); | ||
2142 | if (pw_decay) | ||
2143 | *pw_decay = (short)(hr.u.c.param2 & 0xFFFF); | ||
2144 | if (pw_ratio100) | ||
2145 | *pw_ratio100 = (short)(hr.u.c.param1 >> 16); | ||
2146 | |||
2147 | if (pn_threshold0_01dB) | ||
2148 | *pn_threshold0_01dB = hr.u.c.an_log_value[0]; | ||
2149 | if (pn_makeup_gain0_01dB) | ||
2150 | *pn_makeup_gain0_01dB = hr.u.c.an_log_value[1]; | ||
2151 | |||
2152 | return hr.error; | ||
2153 | } | ||
2154 | |||
2155 | u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2156 | short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB) | ||
2157 | { | ||
2158 | struct hpi_message hm; | ||
2159 | struct hpi_response hr; | ||
2160 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2161 | HPI_CONTROL_GET_STATE); | ||
2162 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2163 | hm.u.c.attribute = HPI_LEVEL_RANGE; | ||
2164 | |||
2165 | hpi_send_recv(&hm, &hr); | ||
2166 | if (hr.error) { | ||
2167 | hr.u.c.an_log_value[0] = 0; | ||
2168 | hr.u.c.an_log_value[1] = 0; | ||
2169 | hr.u.c.param1 = 0; | ||
2170 | } | ||
2171 | if (min_gain_01dB) | ||
2172 | *min_gain_01dB = hr.u.c.an_log_value[0]; | ||
2173 | if (max_gain_01dB) | ||
2174 | *max_gain_01dB = hr.u.c.an_log_value[1]; | ||
2175 | if (step_gain_01dB) | ||
2176 | *step_gain_01dB = (short)hr.u.c.param1; | ||
2177 | return hr.error; | ||
2178 | } | ||
2179 | |||
2180 | u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2181 | short an_gain0_01dB[HPI_MAX_CHANNELS] | ||
2182 | ) | ||
2183 | { | ||
2184 | struct hpi_message hm; | ||
2185 | struct hpi_response hr; | ||
2186 | |||
2187 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2188 | HPI_CONTROL_SET_STATE); | ||
2189 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2190 | memcpy(hm.u.c.an_log_value, an_gain0_01dB, | ||
2191 | sizeof(short) * HPI_MAX_CHANNELS); | ||
2192 | hm.u.c.attribute = HPI_LEVEL_GAIN; | ||
2193 | |||
2194 | hpi_send_recv(&hm, &hr); | ||
2195 | |||
2196 | return hr.error; | ||
2197 | } | ||
2198 | |||
2199 | u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2200 | short an_gain0_01dB[HPI_MAX_CHANNELS] | ||
2201 | ) | ||
2202 | { | ||
2203 | struct hpi_message hm; | ||
2204 | struct hpi_response hr; | ||
2205 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2206 | HPI_CONTROL_GET_STATE); | ||
2207 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2208 | hm.u.c.attribute = HPI_LEVEL_GAIN; | ||
2209 | |||
2210 | hpi_send_recv(&hm, &hr); | ||
2211 | |||
2212 | memcpy(an_gain0_01dB, hr.u.c.an_log_value, | ||
2213 | sizeof(short) * HPI_MAX_CHANNELS); | ||
2214 | return hr.error; | ||
2215 | } | ||
2216 | |||
2217 | u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys, | ||
2218 | const u32 h_meter, u32 *p_channels) | ||
2219 | { | ||
2220 | return hpi_control_query(ph_subsys, h_meter, HPI_METER_NUM_CHANNELS, | ||
2221 | 0, 0, p_channels); | ||
2222 | } | ||
2223 | |||
2224 | u16 hpi_meter_get_peak(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2225 | short an_peakdB[HPI_MAX_CHANNELS] | ||
2226 | ) | ||
2227 | { | ||
2228 | short i = 0; | ||
2229 | |||
2230 | struct hpi_message hm; | ||
2231 | struct hpi_response hr; | ||
2232 | |||
2233 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2234 | HPI_CONTROL_GET_STATE); | ||
2235 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2236 | hm.obj_index = hm.obj_index; | ||
2237 | hm.u.c.attribute = HPI_METER_PEAK; | ||
2238 | |||
2239 | hpi_send_recv(&hm, &hr); | ||
2240 | |||
2241 | if (!hr.error) | ||
2242 | memcpy(an_peakdB, hr.u.c.an_log_value, | ||
2243 | sizeof(short) * HPI_MAX_CHANNELS); | ||
2244 | else | ||
2245 | for (i = 0; i < HPI_MAX_CHANNELS; i++) | ||
2246 | an_peakdB[i] = HPI_METER_MINIMUM; | ||
2247 | return hr.error; | ||
2248 | } | ||
2249 | |||
2250 | u16 hpi_meter_get_rms(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2251 | short an_rmsdB[HPI_MAX_CHANNELS] | ||
2252 | ) | ||
2253 | { | ||
2254 | short i = 0; | ||
2255 | |||
2256 | struct hpi_message hm; | ||
2257 | struct hpi_response hr; | ||
2258 | |||
2259 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2260 | HPI_CONTROL_GET_STATE); | ||
2261 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2262 | hm.u.c.attribute = HPI_METER_RMS; | ||
2263 | |||
2264 | hpi_send_recv(&hm, &hr); | ||
2265 | |||
2266 | if (!hr.error) | ||
2267 | memcpy(an_rmsdB, hr.u.c.an_log_value, | ||
2268 | sizeof(short) * HPI_MAX_CHANNELS); | ||
2269 | else | ||
2270 | for (i = 0; i < HPI_MAX_CHANNELS; i++) | ||
2271 | an_rmsdB[i] = HPI_METER_MINIMUM; | ||
2272 | |||
2273 | return hr.error; | ||
2274 | } | ||
2275 | |||
2276 | u16 hpi_meter_set_rms_ballistics(const struct hpi_hsubsys *ph_subsys, | ||
2277 | u32 h_control, u16 attack, u16 decay) | ||
2278 | { | ||
2279 | return hpi_control_param_set(ph_subsys, h_control, | ||
2280 | HPI_METER_RMS_BALLISTICS, attack, decay); | ||
2281 | } | ||
2282 | |||
2283 | u16 hpi_meter_get_rms_ballistics(const struct hpi_hsubsys *ph_subsys, | ||
2284 | u32 h_control, u16 *pn_attack, u16 *pn_decay) | ||
2285 | { | ||
2286 | u32 attack; | ||
2287 | u32 decay; | ||
2288 | u16 error; | ||
2289 | |||
2290 | error = hpi_control_param2_get(ph_subsys, h_control, | ||
2291 | HPI_METER_RMS_BALLISTICS, &attack, &decay); | ||
2292 | |||
2293 | if (pn_attack) | ||
2294 | *pn_attack = (unsigned short)attack; | ||
2295 | if (pn_decay) | ||
2296 | *pn_decay = (unsigned short)decay; | ||
2297 | |||
2298 | return error; | ||
2299 | } | ||
2300 | |||
2301 | u16 hpi_meter_set_peak_ballistics(const struct hpi_hsubsys *ph_subsys, | ||
2302 | u32 h_control, u16 attack, u16 decay) | ||
2303 | { | ||
2304 | return hpi_control_param_set(ph_subsys, h_control, | ||
2305 | HPI_METER_PEAK_BALLISTICS, attack, decay); | ||
2306 | } | ||
2307 | |||
2308 | u16 hpi_meter_get_peak_ballistics(const struct hpi_hsubsys *ph_subsys, | ||
2309 | u32 h_control, u16 *pn_attack, u16 *pn_decay) | ||
2310 | { | ||
2311 | u32 attack; | ||
2312 | u32 decay; | ||
2313 | u16 error; | ||
2314 | |||
2315 | error = hpi_control_param2_get(ph_subsys, h_control, | ||
2316 | HPI_METER_PEAK_BALLISTICS, &attack, &decay); | ||
2317 | |||
2318 | if (pn_attack) | ||
2319 | *pn_attack = (short)attack; | ||
2320 | if (pn_decay) | ||
2321 | *pn_decay = (short)decay; | ||
2322 | |||
2323 | return error; | ||
2324 | } | ||
2325 | |||
2326 | u16 hpi_microphone_set_phantom_power(const struct hpi_hsubsys *ph_subsys, | ||
2327 | u32 h_control, u16 on_off) | ||
2328 | { | ||
2329 | return hpi_control_param_set(ph_subsys, h_control, | ||
2330 | HPI_MICROPHONE_PHANTOM_POWER, (u32)on_off, 0); | ||
2331 | } | ||
2332 | |||
2333 | u16 hpi_microphone_get_phantom_power(const struct hpi_hsubsys *ph_subsys, | ||
2334 | u32 h_control, u16 *pw_on_off) | ||
2335 | { | ||
2336 | u16 error = 0; | ||
2337 | u32 on_off = 0; | ||
2338 | error = hpi_control_param1_get(ph_subsys, h_control, | ||
2339 | HPI_MICROPHONE_PHANTOM_POWER, &on_off); | ||
2340 | if (pw_on_off) | ||
2341 | *pw_on_off = (u16)on_off; | ||
2342 | return error; | ||
2343 | } | ||
2344 | |||
2345 | u16 hpi_multiplexer_set_source(const struct hpi_hsubsys *ph_subsys, | ||
2346 | u32 h_control, u16 source_node_type, u16 source_node_index) | ||
2347 | { | ||
2348 | return hpi_control_param_set(ph_subsys, h_control, | ||
2349 | HPI_MULTIPLEXER_SOURCE, source_node_type, source_node_index); | ||
2350 | } | ||
2351 | |||
2352 | u16 hpi_multiplexer_get_source(const struct hpi_hsubsys *ph_subsys, | ||
2353 | u32 h_control, u16 *source_node_type, u16 *source_node_index) | ||
2354 | { | ||
2355 | u32 node, index; | ||
2356 | u16 error = hpi_control_param2_get(ph_subsys, h_control, | ||
2357 | HPI_MULTIPLEXER_SOURCE, &node, | ||
2358 | &index); | ||
2359 | if (source_node_type) | ||
2360 | *source_node_type = (u16)node; | ||
2361 | if (source_node_index) | ||
2362 | *source_node_index = (u16)index; | ||
2363 | return error; | ||
2364 | } | ||
2365 | |||
2366 | u16 hpi_multiplexer_query_source(const struct hpi_hsubsys *ph_subsys, | ||
2367 | u32 h_control, u16 index, u16 *source_node_type, | ||
2368 | u16 *source_node_index) | ||
2369 | { | ||
2370 | struct hpi_message hm; | ||
2371 | struct hpi_response hr; | ||
2372 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2373 | HPI_CONTROL_GET_STATE); | ||
2374 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2375 | hm.u.c.attribute = HPI_MULTIPLEXER_QUERYSOURCE; | ||
2376 | hm.u.c.param1 = index; | ||
2377 | |||
2378 | hpi_send_recv(&hm, &hr); | ||
2379 | |||
2380 | if (source_node_type) | ||
2381 | *source_node_type = (u16)hr.u.c.param1; | ||
2382 | if (source_node_index) | ||
2383 | *source_node_index = (u16)hr.u.c.param2; | ||
2384 | return hr.error; | ||
2385 | } | ||
2386 | |||
2387 | u16 hpi_parametricEQ__get_info(const struct hpi_hsubsys *ph_subsys, | ||
2388 | u32 h_control, u16 *pw_number_of_bands, u16 *pw_on_off) | ||
2389 | { | ||
2390 | u32 oB = 0; | ||
2391 | u32 oO = 0; | ||
2392 | u16 error = 0; | ||
2393 | |||
2394 | error = hpi_control_param2_get(ph_subsys, h_control, | ||
2395 | HPI_EQUALIZER_NUM_FILTERS, &oO, &oB); | ||
2396 | if (pw_number_of_bands) | ||
2397 | *pw_number_of_bands = (u16)oB; | ||
2398 | if (pw_on_off) | ||
2399 | *pw_on_off = (u16)oO; | ||
2400 | return error; | ||
2401 | } | ||
2402 | |||
2403 | u16 hpi_parametricEQ__set_state(const struct hpi_hsubsys *ph_subsys, | ||
2404 | u32 h_control, u16 on_off) | ||
2405 | { | ||
2406 | return hpi_control_param_set(ph_subsys, h_control, | ||
2407 | HPI_EQUALIZER_NUM_FILTERS, on_off, 0); | ||
2408 | } | ||
2409 | |||
2410 | u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys, | ||
2411 | u32 h_control, u16 index, u16 *pn_type, u32 *pfrequency_hz, | ||
2412 | short *pnQ100, short *pn_gain0_01dB) | ||
2413 | { | ||
2414 | struct hpi_message hm; | ||
2415 | struct hpi_response hr; | ||
2416 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2417 | HPI_CONTROL_GET_STATE); | ||
2418 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2419 | hm.u.c.attribute = HPI_EQUALIZER_FILTER; | ||
2420 | hm.u.c.param2 = index; | ||
2421 | |||
2422 | hpi_send_recv(&hm, &hr); | ||
2423 | |||
2424 | if (pfrequency_hz) | ||
2425 | *pfrequency_hz = hr.u.c.param1; | ||
2426 | if (pn_type) | ||
2427 | *pn_type = (u16)(hr.u.c.param2 >> 16); | ||
2428 | if (pnQ100) | ||
2429 | *pnQ100 = hr.u.c.an_log_value[1]; | ||
2430 | if (pn_gain0_01dB) | ||
2431 | *pn_gain0_01dB = hr.u.c.an_log_value[0]; | ||
2432 | |||
2433 | return hr.error; | ||
2434 | } | ||
2435 | |||
2436 | u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys, | ||
2437 | u32 h_control, u16 index, u16 type, u32 frequency_hz, short q100, | ||
2438 | short gain0_01dB) | ||
2439 | { | ||
2440 | struct hpi_message hm; | ||
2441 | struct hpi_response hr; | ||
2442 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2443 | HPI_CONTROL_SET_STATE); | ||
2444 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2445 | |||
2446 | hm.u.c.param1 = frequency_hz; | ||
2447 | hm.u.c.param2 = (index & 0xFFFFL) + ((u32)type << 16); | ||
2448 | hm.u.c.an_log_value[0] = gain0_01dB; | ||
2449 | hm.u.c.an_log_value[1] = q100; | ||
2450 | hm.u.c.attribute = HPI_EQUALIZER_FILTER; | ||
2451 | |||
2452 | hpi_send_recv(&hm, &hr); | ||
2453 | |||
2454 | return hr.error; | ||
2455 | } | ||
2456 | |||
2457 | u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys, | ||
2458 | u32 h_control, u16 index, short coeffs[5] | ||
2459 | ) | ||
2460 | { | ||
2461 | struct hpi_message hm; | ||
2462 | struct hpi_response hr; | ||
2463 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2464 | HPI_CONTROL_GET_STATE); | ||
2465 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2466 | hm.u.c.attribute = HPI_EQUALIZER_COEFFICIENTS; | ||
2467 | hm.u.c.param2 = index; | ||
2468 | |||
2469 | hpi_send_recv(&hm, &hr); | ||
2470 | |||
2471 | coeffs[0] = (short)hr.u.c.an_log_value[0]; | ||
2472 | coeffs[1] = (short)hr.u.c.an_log_value[1]; | ||
2473 | coeffs[2] = (short)hr.u.c.param1; | ||
2474 | coeffs[3] = (short)(hr.u.c.param1 >> 16); | ||
2475 | coeffs[4] = (short)hr.u.c.param2; | ||
2476 | |||
2477 | return hr.error; | ||
2478 | } | ||
2479 | |||
2480 | u16 hpi_sample_clock_query_source(const struct hpi_hsubsys *ph_subsys, | ||
2481 | const u32 h_clock, const u32 index, u16 *pw_source) | ||
2482 | { | ||
2483 | u32 qr; | ||
2484 | u16 err; | ||
2485 | |||
2486 | err = hpi_control_query(ph_subsys, h_clock, HPI_SAMPLECLOCK_SOURCE, | ||
2487 | index, 0, &qr); | ||
2488 | *pw_source = (u16)qr; | ||
2489 | return err; | ||
2490 | } | ||
2491 | |||
2492 | u16 hpi_sample_clock_set_source(const struct hpi_hsubsys *ph_subsys, | ||
2493 | u32 h_control, u16 source) | ||
2494 | { | ||
2495 | return hpi_control_param_set(ph_subsys, h_control, | ||
2496 | HPI_SAMPLECLOCK_SOURCE, source, 0); | ||
2497 | } | ||
2498 | |||
2499 | u16 hpi_sample_clock_get_source(const struct hpi_hsubsys *ph_subsys, | ||
2500 | u32 h_control, u16 *pw_source) | ||
2501 | { | ||
2502 | u16 error = 0; | ||
2503 | u32 source = 0; | ||
2504 | error = hpi_control_param1_get(ph_subsys, h_control, | ||
2505 | HPI_SAMPLECLOCK_SOURCE, &source); | ||
2506 | if (!error) | ||
2507 | if (pw_source) | ||
2508 | *pw_source = (u16)source; | ||
2509 | return error; | ||
2510 | } | ||
2511 | |||
2512 | u16 hpi_sample_clock_query_source_index(const struct hpi_hsubsys *ph_subsys, | ||
2513 | const u32 h_clock, const u32 index, const u32 source, | ||
2514 | u16 *pw_source_index) | ||
2515 | { | ||
2516 | u32 qr; | ||
2517 | u16 err; | ||
2518 | |||
2519 | err = hpi_control_query(ph_subsys, h_clock, | ||
2520 | HPI_SAMPLECLOCK_SOURCE_INDEX, index, source, &qr); | ||
2521 | *pw_source_index = (u16)qr; | ||
2522 | return err; | ||
2523 | } | ||
2524 | |||
2525 | u16 hpi_sample_clock_set_source_index(const struct hpi_hsubsys *ph_subsys, | ||
2526 | u32 h_control, u16 source_index) | ||
2527 | { | ||
2528 | return hpi_control_param_set(ph_subsys, h_control, | ||
2529 | HPI_SAMPLECLOCK_SOURCE_INDEX, source_index, 0); | ||
2530 | } | ||
2531 | |||
2532 | u16 hpi_sample_clock_get_source_index(const struct hpi_hsubsys *ph_subsys, | ||
2533 | u32 h_control, u16 *pw_source_index) | ||
2534 | { | ||
2535 | u16 error = 0; | ||
2536 | u32 source_index = 0; | ||
2537 | error = hpi_control_param1_get(ph_subsys, h_control, | ||
2538 | HPI_SAMPLECLOCK_SOURCE_INDEX, &source_index); | ||
2539 | if (!error) | ||
2540 | if (pw_source_index) | ||
2541 | *pw_source_index = (u16)source_index; | ||
2542 | return error; | ||
2543 | } | ||
2544 | |||
2545 | u16 hpi_sample_clock_query_local_rate(const struct hpi_hsubsys *ph_subsys, | ||
2546 | const u32 h_clock, const u32 index, u32 *prate) | ||
2547 | { | ||
2548 | u16 err; | ||
2549 | err = hpi_control_query(ph_subsys, h_clock, | ||
2550 | HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, index, 0, prate); | ||
2551 | |||
2552 | return err; | ||
2553 | } | ||
2554 | |||
2555 | u16 hpi_sample_clock_set_local_rate(const struct hpi_hsubsys *ph_subsys, | ||
2556 | u32 h_control, u32 sample_rate) | ||
2557 | { | ||
2558 | return hpi_control_param_set(ph_subsys, h_control, | ||
2559 | HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, sample_rate, 0); | ||
2560 | } | ||
2561 | |||
2562 | u16 hpi_sample_clock_get_local_rate(const struct hpi_hsubsys *ph_subsys, | ||
2563 | u32 h_control, u32 *psample_rate) | ||
2564 | { | ||
2565 | u16 error = 0; | ||
2566 | u32 sample_rate = 0; | ||
2567 | error = hpi_control_param1_get(ph_subsys, h_control, | ||
2568 | HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, &sample_rate); | ||
2569 | if (!error) | ||
2570 | if (psample_rate) | ||
2571 | *psample_rate = sample_rate; | ||
2572 | return error; | ||
2573 | } | ||
2574 | |||
2575 | u16 hpi_sample_clock_get_sample_rate(const struct hpi_hsubsys *ph_subsys, | ||
2576 | u32 h_control, u32 *psample_rate) | ||
2577 | { | ||
2578 | u16 error = 0; | ||
2579 | u32 sample_rate = 0; | ||
2580 | error = hpi_control_param1_get(ph_subsys, h_control, | ||
2581 | HPI_SAMPLECLOCK_SAMPLERATE, &sample_rate); | ||
2582 | if (!error) | ||
2583 | if (psample_rate) | ||
2584 | *psample_rate = sample_rate; | ||
2585 | return error; | ||
2586 | } | ||
2587 | |||
2588 | u16 hpi_sample_clock_set_auto(const struct hpi_hsubsys *ph_subsys, | ||
2589 | u32 h_control, u32 enable) | ||
2590 | { | ||
2591 | return hpi_control_param_set(ph_subsys, h_control, | ||
2592 | HPI_SAMPLECLOCK_AUTO, enable, 0); | ||
2593 | } | ||
2594 | |||
2595 | u16 hpi_sample_clock_get_auto(const struct hpi_hsubsys *ph_subsys, | ||
2596 | u32 h_control, u32 *penable) | ||
2597 | { | ||
2598 | return hpi_control_param1_get(ph_subsys, h_control, | ||
2599 | HPI_SAMPLECLOCK_AUTO, penable); | ||
2600 | } | ||
2601 | |||
2602 | u16 hpi_sample_clock_set_local_rate_lock(const struct hpi_hsubsys *ph_subsys, | ||
2603 | u32 h_control, u32 lock) | ||
2604 | { | ||
2605 | return hpi_control_param_set(ph_subsys, h_control, | ||
2606 | HPI_SAMPLECLOCK_LOCAL_LOCK, lock, 0); | ||
2607 | } | ||
2608 | |||
2609 | u16 hpi_sample_clock_get_local_rate_lock(const struct hpi_hsubsys *ph_subsys, | ||
2610 | u32 h_control, u32 *plock) | ||
2611 | { | ||
2612 | return hpi_control_param1_get(ph_subsys, h_control, | ||
2613 | HPI_SAMPLECLOCK_LOCAL_LOCK, plock); | ||
2614 | } | ||
2615 | |||
2616 | u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys, | ||
2617 | u32 h_control, u32 index, u32 *frequency) | ||
2618 | { | ||
2619 | return hpi_control_param_get(ph_subsys, h_control, | ||
2620 | HPI_TONEDETECTOR_FREQUENCY, index, 0, frequency, NULL); | ||
2621 | } | ||
2622 | |||
2623 | u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys, | ||
2624 | u32 h_control, u32 *state) | ||
2625 | { | ||
2626 | return hpi_control_param_get(ph_subsys, h_control, | ||
2627 | HPI_TONEDETECTOR_STATE, 0, 0, (u32 *)state, NULL); | ||
2628 | } | ||
2629 | |||
2630 | u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, | ||
2631 | u32 h_control, u32 enable) | ||
2632 | { | ||
2633 | return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE, | ||
2634 | (u32)enable, 0); | ||
2635 | } | ||
2636 | |||
2637 | u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys, | ||
2638 | u32 h_control, u32 *enable) | ||
2639 | { | ||
2640 | return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE, | ||
2641 | 0, 0, (u32 *)enable, NULL); | ||
2642 | } | ||
2643 | |||
2644 | u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, | ||
2645 | u32 h_control, u32 event_enable) | ||
2646 | { | ||
2647 | return hpi_control_param_set(ph_subsys, h_control, | ||
2648 | HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0); | ||
2649 | } | ||
2650 | |||
2651 | u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, | ||
2652 | u32 h_control, u32 *event_enable) | ||
2653 | { | ||
2654 | return hpi_control_param_get(ph_subsys, h_control, | ||
2655 | HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL); | ||
2656 | } | ||
2657 | |||
2658 | u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, | ||
2659 | u32 h_control, int threshold) | ||
2660 | { | ||
2661 | return hpi_control_param_set(ph_subsys, h_control, | ||
2662 | HPI_TONEDETECTOR_THRESHOLD, (u32)threshold, 0); | ||
2663 | } | ||
2664 | |||
2665 | u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, | ||
2666 | u32 h_control, int *threshold) | ||
2667 | { | ||
2668 | return hpi_control_param_get(ph_subsys, h_control, | ||
2669 | HPI_TONEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL); | ||
2670 | } | ||
2671 | |||
2672 | u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys, | ||
2673 | u32 h_control, u32 *state) | ||
2674 | { | ||
2675 | return hpi_control_param_get(ph_subsys, h_control, | ||
2676 | HPI_SILENCEDETECTOR_STATE, 0, 0, (u32 *)state, NULL); | ||
2677 | } | ||
2678 | |||
2679 | u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys, | ||
2680 | u32 h_control, u32 enable) | ||
2681 | { | ||
2682 | return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE, | ||
2683 | (u32)enable, 0); | ||
2684 | } | ||
2685 | |||
2686 | u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys, | ||
2687 | u32 h_control, u32 *enable) | ||
2688 | { | ||
2689 | return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE, | ||
2690 | 0, 0, (u32 *)enable, NULL); | ||
2691 | } | ||
2692 | |||
2693 | u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys, | ||
2694 | u32 h_control, u32 event_enable) | ||
2695 | { | ||
2696 | return hpi_control_param_set(ph_subsys, h_control, | ||
2697 | HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0); | ||
2698 | } | ||
2699 | |||
2700 | u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys, | ||
2701 | u32 h_control, u32 *event_enable) | ||
2702 | { | ||
2703 | return hpi_control_param_get(ph_subsys, h_control, | ||
2704 | HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL); | ||
2705 | } | ||
2706 | |||
2707 | u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys, | ||
2708 | u32 h_control, u32 delay) | ||
2709 | { | ||
2710 | return hpi_control_param_set(ph_subsys, h_control, | ||
2711 | HPI_SILENCEDETECTOR_DELAY, (u32)delay, 0); | ||
2712 | } | ||
2713 | |||
2714 | u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys, | ||
2715 | u32 h_control, u32 *delay) | ||
2716 | { | ||
2717 | return hpi_control_param_get(ph_subsys, h_control, | ||
2718 | HPI_SILENCEDETECTOR_DELAY, 0, 0, (u32 *)delay, NULL); | ||
2719 | } | ||
2720 | |||
2721 | u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys, | ||
2722 | u32 h_control, int threshold) | ||
2723 | { | ||
2724 | return hpi_control_param_set(ph_subsys, h_control, | ||
2725 | HPI_SILENCEDETECTOR_THRESHOLD, (u32)threshold, 0); | ||
2726 | } | ||
2727 | |||
2728 | u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys, | ||
2729 | u32 h_control, int *threshold) | ||
2730 | { | ||
2731 | return hpi_control_param_get(ph_subsys, h_control, | ||
2732 | HPI_SILENCEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL); | ||
2733 | } | ||
2734 | |||
2735 | u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys, | ||
2736 | const u32 h_tuner, const u32 index, u16 *pw_band) | ||
2737 | { | ||
2738 | u32 qr; | ||
2739 | u16 err; | ||
2740 | |||
2741 | err = hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_BAND, index, 0, | ||
2742 | &qr); | ||
2743 | *pw_band = (u16)qr; | ||
2744 | return err; | ||
2745 | } | ||
2746 | |||
2747 | u16 hpi_tuner_set_band(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2748 | u16 band) | ||
2749 | { | ||
2750 | return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_BAND, | ||
2751 | band, 0); | ||
2752 | } | ||
2753 | |||
2754 | u16 hpi_tuner_get_band(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2755 | u16 *pw_band) | ||
2756 | { | ||
2757 | u32 band = 0; | ||
2758 | u16 error = 0; | ||
2759 | |||
2760 | error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_BAND, | ||
2761 | &band); | ||
2762 | if (pw_band) | ||
2763 | *pw_band = (u16)band; | ||
2764 | return error; | ||
2765 | } | ||
2766 | |||
2767 | u16 hpi_tuner_query_frequency(const struct hpi_hsubsys *ph_subsys, | ||
2768 | const u32 h_tuner, const u32 index, const u16 band, u32 *pfreq) | ||
2769 | { | ||
2770 | return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_FREQ, index, | ||
2771 | band, pfreq); | ||
2772 | } | ||
2773 | |||
2774 | u16 hpi_tuner_set_frequency(const struct hpi_hsubsys *ph_subsys, | ||
2775 | u32 h_control, u32 freq_ink_hz) | ||
2776 | { | ||
2777 | return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_FREQ, | ||
2778 | freq_ink_hz, 0); | ||
2779 | } | ||
2780 | |||
2781 | u16 hpi_tuner_get_frequency(const struct hpi_hsubsys *ph_subsys, | ||
2782 | u32 h_control, u32 *pw_freq_ink_hz) | ||
2783 | { | ||
2784 | return hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_FREQ, | ||
2785 | pw_freq_ink_hz); | ||
2786 | } | ||
2787 | |||
2788 | u16 hpi_tuner_query_gain(const struct hpi_hsubsys *ph_subsys, | ||
2789 | const u32 h_tuner, const u32 index, u16 *pw_gain) | ||
2790 | { | ||
2791 | u32 qr; | ||
2792 | u16 err; | ||
2793 | |||
2794 | err = hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_BAND, index, 0, | ||
2795 | &qr); | ||
2796 | *pw_gain = (u16)qr; | ||
2797 | return err; | ||
2798 | } | ||
2799 | |||
2800 | u16 hpi_tuner_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2801 | short gain) | ||
2802 | { | ||
2803 | return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_GAIN, | ||
2804 | gain, 0); | ||
2805 | } | ||
2806 | |||
2807 | u16 hpi_tuner_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2808 | short *pn_gain) | ||
2809 | { | ||
2810 | u32 gain = 0; | ||
2811 | u16 error = 0; | ||
2812 | |||
2813 | error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_GAIN, | ||
2814 | &gain); | ||
2815 | if (pn_gain) | ||
2816 | *pn_gain = (u16)gain; | ||
2817 | return error; | ||
2818 | } | ||
2819 | |||
2820 | u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2821 | short *pw_level) | ||
2822 | { | ||
2823 | struct hpi_message hm; | ||
2824 | struct hpi_response hr; | ||
2825 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2826 | HPI_CONTROL_GET_STATE); | ||
2827 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2828 | hm.u.c.attribute = HPI_TUNER_LEVEL; | ||
2829 | hm.u.c.param1 = HPI_TUNER_LEVEL_AVERAGE; | ||
2830 | hpi_send_recv(&hm, &hr); | ||
2831 | if (pw_level) | ||
2832 | *pw_level = (short)hr.u.c.param1; | ||
2833 | return hr.error; | ||
2834 | } | ||
2835 | |||
2836 | u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys, | ||
2837 | u32 h_control, short *pw_level) | ||
2838 | { | ||
2839 | struct hpi_message hm; | ||
2840 | struct hpi_response hr; | ||
2841 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2842 | HPI_CONTROL_GET_STATE); | ||
2843 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2844 | hm.u.c.attribute = HPI_TUNER_LEVEL; | ||
2845 | hm.u.c.param1 = HPI_TUNER_LEVEL_RAW; | ||
2846 | hpi_send_recv(&hm, &hr); | ||
2847 | if (pw_level) | ||
2848 | *pw_level = (short)hr.u.c.param1; | ||
2849 | return hr.error; | ||
2850 | } | ||
2851 | |||
2852 | u16 hpi_tuner_query_deemphasis(const struct hpi_hsubsys *ph_subsys, | ||
2853 | const u32 h_tuner, const u32 index, const u16 band, u32 *pdeemphasis) | ||
2854 | { | ||
2855 | return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_DEEMPHASIS, | ||
2856 | index, band, pdeemphasis); | ||
2857 | } | ||
2858 | |||
2859 | u16 hpi_tuner_set_deemphasis(const struct hpi_hsubsys *ph_subsys, | ||
2860 | u32 h_control, u32 deemphasis) | ||
2861 | { | ||
2862 | return hpi_control_param_set(ph_subsys, h_control, | ||
2863 | HPI_TUNER_DEEMPHASIS, deemphasis, 0); | ||
2864 | } | ||
2865 | |||
2866 | u16 hpi_tuner_get_deemphasis(const struct hpi_hsubsys *ph_subsys, | ||
2867 | u32 h_control, u32 *pdeemphasis) | ||
2868 | { | ||
2869 | return hpi_control_param1_get(ph_subsys, h_control, | ||
2870 | HPI_TUNER_DEEMPHASIS, pdeemphasis); | ||
2871 | } | ||
2872 | |||
2873 | u16 hpi_tuner_query_program(const struct hpi_hsubsys *ph_subsys, | ||
2874 | const u32 h_tuner, u32 *pbitmap_program) | ||
2875 | { | ||
2876 | return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_PROGRAM, 0, 0, | ||
2877 | pbitmap_program); | ||
2878 | } | ||
2879 | |||
2880 | u16 hpi_tuner_set_program(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2881 | u32 program) | ||
2882 | { | ||
2883 | return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_PROGRAM, | ||
2884 | program, 0); | ||
2885 | } | ||
2886 | |||
2887 | u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2888 | u32 *pprogram) | ||
2889 | { | ||
2890 | return hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_PROGRAM, | ||
2891 | pprogram); | ||
2892 | } | ||
2893 | |||
2894 | u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys, | ||
2895 | u32 h_control, char *psz_dsp_version, const u32 string_size) | ||
2896 | { | ||
2897 | return hpi_control_get_string(ph_subsys, h_control, | ||
2898 | HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size); | ||
2899 | } | ||
2900 | |||
2901 | u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys, | ||
2902 | u32 h_control, char *psz_sdk_version, const u32 string_size) | ||
2903 | { | ||
2904 | return hpi_control_get_string(ph_subsys, h_control, | ||
2905 | HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size); | ||
2906 | } | ||
2907 | |||
2908 | u16 hpi_tuner_get_status(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2909 | u16 *pw_status_mask, u16 *pw_status) | ||
2910 | { | ||
2911 | u32 status = 0; | ||
2912 | u16 error = 0; | ||
2913 | |||
2914 | error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_STATUS, | ||
2915 | &status); | ||
2916 | if (pw_status) { | ||
2917 | if (!error) { | ||
2918 | *pw_status_mask = (u16)(status >> 16); | ||
2919 | *pw_status = (u16)(status & 0xFFFF); | ||
2920 | } else { | ||
2921 | *pw_status_mask = 0; | ||
2922 | *pw_status = 0; | ||
2923 | } | ||
2924 | } | ||
2925 | return error; | ||
2926 | } | ||
2927 | |||
2928 | u16 hpi_tuner_set_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2929 | u32 mode, u32 value) | ||
2930 | { | ||
2931 | return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_MODE, | ||
2932 | mode, value); | ||
2933 | } | ||
2934 | |||
2935 | u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2936 | u32 mode, u32 *pn_value) | ||
2937 | { | ||
2938 | return hpi_control_param_get(ph_subsys, h_control, HPI_TUNER_MODE, | ||
2939 | mode, 0, pn_value, NULL); | ||
2940 | } | ||
2941 | |||
2942 | u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys, | ||
2943 | u32 h_control, u32 *pquality) | ||
2944 | { | ||
2945 | return hpi_control_param_get(ph_subsys, h_control, | ||
2946 | HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL); | ||
2947 | } | ||
2948 | |||
2949 | u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2950 | char *p_data) | ||
2951 | { | ||
2952 | struct hpi_message hm; | ||
2953 | struct hpi_response hr; | ||
2954 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
2955 | HPI_CONTROL_GET_STATE); | ||
2956 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
2957 | hm.u.c.attribute = HPI_TUNER_RDS; | ||
2958 | hpi_send_recv(&hm, &hr); | ||
2959 | if (p_data) { | ||
2960 | *(u32 *)&p_data[0] = hr.u.cu.tuner.rds.data[0]; | ||
2961 | *(u32 *)&p_data[4] = hr.u.cu.tuner.rds.data[1]; | ||
2962 | *(u32 *)&p_data[8] = hr.u.cu.tuner.rds.bLER; | ||
2963 | } | ||
2964 | return hr.error; | ||
2965 | } | ||
2966 | |||
2967 | u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys, | ||
2968 | u32 h_control, char *psz_string, const u32 data_length) | ||
2969 | { | ||
2970 | return hpi_control_get_string(ph_subsys, h_control, | ||
2971 | HPI_PAD_CHANNEL_NAME, psz_string, data_length); | ||
2972 | } | ||
2973 | |||
2974 | u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2975 | char *psz_string, const u32 data_length) | ||
2976 | { | ||
2977 | return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_ARTIST, | ||
2978 | psz_string, data_length); | ||
2979 | } | ||
2980 | |||
2981 | u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2982 | char *psz_string, const u32 data_length) | ||
2983 | { | ||
2984 | return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_TITLE, | ||
2985 | psz_string, data_length); | ||
2986 | } | ||
2987 | |||
2988 | u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
2989 | char *psz_string, const u32 data_length) | ||
2990 | { | ||
2991 | return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_COMMENT, | ||
2992 | psz_string, data_length); | ||
2993 | } | ||
2994 | |||
2995 | u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys, | ||
2996 | u32 h_control, u32 *ppTY) | ||
2997 | { | ||
2998 | return hpi_control_param_get(ph_subsys, h_control, | ||
2999 | HPI_PAD_PROGRAM_TYPE, 0, 0, ppTY, NULL); | ||
3000 | } | ||
3001 | |||
3002 | u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
3003 | u32 *ppI) | ||
3004 | { | ||
3005 | return hpi_control_param_get(ph_subsys, h_control, HPI_PAD_PROGRAM_ID, | ||
3006 | 0, 0, ppI, NULL); | ||
3007 | } | ||
3008 | |||
3009 | u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys, | ||
3010 | const u32 h_volume, u32 *p_channels) | ||
3011 | { | ||
3012 | return hpi_control_query(ph_subsys, h_volume, HPI_VOLUME_NUM_CHANNELS, | ||
3013 | 0, 0, p_channels); | ||
3014 | } | ||
3015 | |||
3016 | u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
3017 | short an_log_gain[HPI_MAX_CHANNELS] | ||
3018 | ) | ||
3019 | { | ||
3020 | struct hpi_message hm; | ||
3021 | struct hpi_response hr; | ||
3022 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
3023 | HPI_CONTROL_SET_STATE); | ||
3024 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
3025 | memcpy(hm.u.c.an_log_value, an_log_gain, | ||
3026 | sizeof(short) * HPI_MAX_CHANNELS); | ||
3027 | hm.u.c.attribute = HPI_VOLUME_GAIN; | ||
3028 | |||
3029 | hpi_send_recv(&hm, &hr); | ||
3030 | |||
3031 | return hr.error; | ||
3032 | } | ||
3033 | |||
3034 | u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
3035 | short an_log_gain[HPI_MAX_CHANNELS] | ||
3036 | ) | ||
3037 | { | ||
3038 | struct hpi_message hm; | ||
3039 | struct hpi_response hr; | ||
3040 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
3041 | HPI_CONTROL_GET_STATE); | ||
3042 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
3043 | hm.u.c.attribute = HPI_VOLUME_GAIN; | ||
3044 | |||
3045 | hpi_send_recv(&hm, &hr); | ||
3046 | |||
3047 | memcpy(an_log_gain, hr.u.c.an_log_value, | ||
3048 | sizeof(short) * HPI_MAX_CHANNELS); | ||
3049 | return hr.error; | ||
3050 | } | ||
3051 | |||
3052 | u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
3053 | short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB) | ||
3054 | { | ||
3055 | struct hpi_message hm; | ||
3056 | struct hpi_response hr; | ||
3057 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
3058 | HPI_CONTROL_GET_STATE); | ||
3059 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
3060 | hm.u.c.attribute = HPI_VOLUME_RANGE; | ||
3061 | |||
3062 | hpi_send_recv(&hm, &hr); | ||
3063 | if (hr.error) { | ||
3064 | hr.u.c.an_log_value[0] = 0; | ||
3065 | hr.u.c.an_log_value[1] = 0; | ||
3066 | hr.u.c.param1 = 0; | ||
3067 | } | ||
3068 | if (min_gain_01dB) | ||
3069 | *min_gain_01dB = hr.u.c.an_log_value[0]; | ||
3070 | if (max_gain_01dB) | ||
3071 | *max_gain_01dB = hr.u.c.an_log_value[1]; | ||
3072 | if (step_gain_01dB) | ||
3073 | *step_gain_01dB = (short)hr.u.c.param1; | ||
3074 | return hr.error; | ||
3075 | } | ||
3076 | |||
3077 | u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys, | ||
3078 | u32 h_control, short an_stop_gain0_01dB[HPI_MAX_CHANNELS], | ||
3079 | u32 duration_ms, u16 profile) | ||
3080 | { | ||
3081 | struct hpi_message hm; | ||
3082 | struct hpi_response hr; | ||
3083 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
3084 | HPI_CONTROL_SET_STATE); | ||
3085 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
3086 | |||
3087 | memcpy(hm.u.c.an_log_value, an_stop_gain0_01dB, | ||
3088 | sizeof(short) * HPI_MAX_CHANNELS); | ||
3089 | |||
3090 | hm.u.c.attribute = HPI_VOLUME_AUTOFADE; | ||
3091 | hm.u.c.param1 = duration_ms; | ||
3092 | hm.u.c.param2 = profile; | ||
3093 | |||
3094 | hpi_send_recv(&hm, &hr); | ||
3095 | |||
3096 | return hr.error; | ||
3097 | } | ||
3098 | |||
3099 | u16 hpi_volume_auto_fade(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
3100 | short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms) | ||
3101 | { | ||
3102 | return hpi_volume_auto_fade_profile(ph_subsys, h_control, | ||
3103 | an_stop_gain0_01dB, duration_ms, HPI_VOLUME_AUTOFADE_LOG); | ||
3104 | } | ||
3105 | |||
3106 | u16 hpi_vox_set_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
3107 | short an_gain0_01dB) | ||
3108 | { | ||
3109 | struct hpi_message hm; | ||
3110 | struct hpi_response hr; | ||
3111 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
3112 | HPI_CONTROL_SET_STATE); | ||
3113 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
3114 | hm.u.c.attribute = HPI_VOX_THRESHOLD; | ||
3115 | |||
3116 | hm.u.c.an_log_value[0] = an_gain0_01dB; | ||
3117 | |||
3118 | hpi_send_recv(&hm, &hr); | ||
3119 | |||
3120 | return hr.error; | ||
3121 | } | ||
3122 | |||
3123 | u16 hpi_vox_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control, | ||
3124 | short *an_gain0_01dB) | ||
3125 | { | ||
3126 | struct hpi_message hm; | ||
3127 | struct hpi_response hr; | ||
3128 | hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL, | ||
3129 | HPI_CONTROL_GET_STATE); | ||
3130 | u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index); | ||
3131 | hm.u.c.attribute = HPI_VOX_THRESHOLD; | ||
3132 | |||
3133 | hpi_send_recv(&hm, &hr); | ||
3134 | |||
3135 | *an_gain0_01dB = hr.u.c.an_log_value[0]; | ||
3136 | |||
3137 | return hr.error; | ||
3138 | } | ||
3139 | |||
3140 | static size_t strv_packet_size = MIN_STRV_PACKET_SIZE; | ||
3141 | |||
3142 | static size_t entity_type_to_size[LAST_ENTITY_TYPE] = { | ||
3143 | 0, | ||
3144 | sizeof(struct hpi_entity), | ||
3145 | sizeof(void *), | ||
3146 | |||
3147 | sizeof(int), | ||
3148 | sizeof(float), | ||
3149 | sizeof(double), | ||
3150 | |||
3151 | sizeof(char), | ||
3152 | sizeof(char), | ||
3153 | |||
3154 | 4 * sizeof(char), | ||
3155 | 16 * sizeof(char), | ||
3156 | 6 * sizeof(char), | ||
3157 | }; | ||
3158 | |||
3159 | inline size_t hpi_entity_size(struct hpi_entity *entity_ptr) | ||
3160 | { | ||
3161 | return entity_ptr->header.size; | ||
3162 | } | ||
3163 | |||
3164 | inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr) | ||
3165 | { | ||
3166 | return sizeof(entity_ptr->header); | ||
3167 | } | ||
3168 | |||
3169 | inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr) | ||
3170 | { | ||
3171 | return hpi_entity_size(entity_ptr) - | ||
3172 | hpi_entity_header_size(entity_ptr); | ||
3173 | } | ||
3174 | |||
3175 | inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr) | ||
3176 | { | ||
3177 | return hpi_entity_value_size(entity_ptr) / | ||
3178 | entity_type_to_size[entity_ptr->header.type]; | ||
3179 | } | ||
3180 | |||
3181 | inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity | ||
3182 | *entity_ptr) | ||
3183 | { | ||
3184 | return (void *)(((uint8_t *) entity_ptr) + | ||
3185 | hpi_entity_size(entity_ptr)); | ||
3186 | } | ||
3187 | |||
3188 | inline u16 hpi_entity_check_type(const enum e_entity_type t) | ||
3189 | { | ||
3190 | if (t >= 0 && t < STR_TYPE_FIELD_MAX) | ||
3191 | return 0; | ||
3192 | return HPI_ERROR_ENTITY_TYPE_INVALID; | ||
3193 | } | ||
3194 | |||
3195 | inline u16 hpi_entity_check_role(const enum e_entity_role r) | ||
3196 | { | ||
3197 | if (r >= 0 && r < STR_ROLE_FIELD_MAX) | ||
3198 | return 0; | ||
3199 | return HPI_ERROR_ENTITY_ROLE_INVALID; | ||
3200 | } | ||
3201 | |||
3202 | static u16 hpi_entity_get_next(struct hpi_entity *entity, int recursive_flag, | ||
3203 | void *guard_p, struct hpi_entity **next) | ||
3204 | { | ||
3205 | HPI_DEBUG_ASSERT(entity != NULL); | ||
3206 | HPI_DEBUG_ASSERT(next != NULL); | ||
3207 | HPI_DEBUG_ASSERT(hpi_entity_size(entity) != 0); | ||
3208 | |||
3209 | if (guard_p <= (void *)entity) { | ||
3210 | *next = NULL; | ||
3211 | return 0; | ||
3212 | } | ||
3213 | |||
3214 | if (recursive_flag && entity->header.type == entity_type_sequence) | ||
3215 | *next = (struct hpi_entity *)entity->value; | ||
3216 | else | ||
3217 | *next = (struct hpi_entity *)hpi_entity_ptr_to_next(entity); | ||
3218 | |||
3219 | if (guard_p <= (void *)*next) { | ||
3220 | *next = NULL; | ||
3221 | return 0; | ||
3222 | } | ||
3223 | |||
3224 | HPI_DEBUG_ASSERT(guard_p >= (void *)hpi_entity_ptr_to_next(*next)); | ||
3225 | return 0; | ||
3226 | } | ||
3227 | |||
3228 | u16 hpi_entity_find_next(struct hpi_entity *container_entity, | ||
3229 | enum e_entity_type type, enum e_entity_role role, int recursive_flag, | ||
3230 | struct hpi_entity **current_match) | ||
3231 | { | ||
3232 | struct hpi_entity *tmp = NULL; | ||
3233 | void *guard_p = NULL; | ||
3234 | |||
3235 | HPI_DEBUG_ASSERT(container_entity != NULL); | ||
3236 | guard_p = hpi_entity_ptr_to_next(container_entity); | ||
3237 | |||
3238 | if (*current_match != NULL) | ||
3239 | hpi_entity_get_next(*current_match, recursive_flag, guard_p, | ||
3240 | &tmp); | ||
3241 | else | ||
3242 | hpi_entity_get_next(container_entity, 1, guard_p, &tmp); | ||
3243 | |||
3244 | while (tmp) { | ||
3245 | u16 err; | ||
3246 | |||
3247 | HPI_DEBUG_ASSERT((void *)tmp >= (void *)container_entity); | ||
3248 | |||
3249 | if ((!type || tmp->header.type == type) && (!role | ||
3250 | || tmp->header.role == role)) { | ||
3251 | *current_match = tmp; | ||
3252 | return 0; | ||
3253 | } | ||
3254 | |||
3255 | err = hpi_entity_get_next(tmp, recursive_flag, guard_p, | ||
3256 | current_match); | ||
3257 | if (err) | ||
3258 | return err; | ||
3259 | |||
3260 | tmp = *current_match; | ||
3261 | } | ||
3262 | |||
3263 | *current_match = NULL; | ||
3264 | return 0; | ||
3265 | } | ||
3266 | |||
3267 | void hpi_entity_free(struct hpi_entity *entity) | ||
3268 | { | ||
3269 | if (entity != NULL) | ||
3270 | kfree(entity); | ||
3271 | } | ||
3272 | |||
3273 | static u16 hpi_entity_alloc_and_copy(struct hpi_entity *src, | ||
3274 | struct hpi_entity **dst) | ||
3275 | { | ||
3276 | size_t buf_size; | ||
3277 | HPI_DEBUG_ASSERT(dst != NULL); | ||
3278 | HPI_DEBUG_ASSERT(src != NULL); | ||
3279 | |||
3280 | buf_size = hpi_entity_size(src); | ||
3281 | *dst = kmalloc(buf_size, GFP_KERNEL); | ||
3282 | if (*dst == NULL) | ||
3283 | return HPI_ERROR_MEMORY_ALLOC; | ||
3284 | memcpy(*dst, src, buf_size); | ||
3285 | return 0; | ||
3286 | } | ||
3287 | |||
3288 | u16 hpi_universal_info(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
3289 | struct hpi_entity **info) | ||
3290 | { | ||
3291 | struct hpi_msg_strv hm; | ||
3292 | struct hpi_res_strv *phr; | ||
3293 | u16 hpi_err; | ||
3294 | int remaining_attempts = 2; | ||
3295 | size_t resp_packet_size = 1024; | ||
3296 | |||
3297 | *info = NULL; | ||
3298 | |||
3299 | while (remaining_attempts--) { | ||
3300 | phr = kmalloc(resp_packet_size, GFP_KERNEL); | ||
3301 | HPI_DEBUG_ASSERT(phr != NULL); | ||
3302 | |||
3303 | hpi_init_message_responseV1(&hm.h, (u16)sizeof(hm), &phr->h, | ||
3304 | (u16)resp_packet_size, HPI_OBJ_CONTROL, | ||
3305 | HPI_CONTROL_GET_INFO); | ||
3306 | u32TOINDEXES(hC, &hm.h.adapter_index, &hm.h.obj_index); | ||
3307 | |||
3308 | hm.strv.header.size = sizeof(hm.strv); | ||
3309 | phr->strv.header.size = resp_packet_size - sizeof(phr->h); | ||
3310 | |||
3311 | hpi_send_recv((struct hpi_message *)&hm.h, | ||
3312 | (struct hpi_response *)&phr->h); | ||
3313 | if (phr->h.error == HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL) { | ||
3314 | |||
3315 | HPI_DEBUG_ASSERT(phr->h.specific_error > | ||
3316 | MIN_STRV_PACKET_SIZE | ||
3317 | && phr->h.specific_error < 1500); | ||
3318 | resp_packet_size = phr->h.specific_error; | ||
3319 | } else { | ||
3320 | remaining_attempts = 0; | ||
3321 | if (!phr->h.error) | ||
3322 | hpi_entity_alloc_and_copy(&phr->strv, info); | ||
3323 | } | ||
3324 | |||
3325 | hpi_err = phr->h.error; | ||
3326 | kfree(phr); | ||
3327 | } | ||
3328 | |||
3329 | return hpi_err; | ||
3330 | } | ||
3331 | |||
3332 | u16 hpi_universal_get(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
3333 | struct hpi_entity **value) | ||
3334 | { | ||
3335 | struct hpi_msg_strv hm; | ||
3336 | struct hpi_res_strv *phr; | ||
3337 | u16 hpi_err; | ||
3338 | int remaining_attempts = 2; | ||
3339 | |||
3340 | *value = NULL; | ||
3341 | |||
3342 | while (remaining_attempts--) { | ||
3343 | phr = kmalloc(strv_packet_size, GFP_KERNEL); | ||
3344 | if (!phr) | ||
3345 | return HPI_ERROR_MEMORY_ALLOC; | ||
3346 | |||
3347 | hpi_init_message_responseV1(&hm.h, (u16)sizeof(hm), &phr->h, | ||
3348 | (u16)strv_packet_size, HPI_OBJ_CONTROL, | ||
3349 | HPI_CONTROL_GET_STATE); | ||
3350 | u32TOINDEXES(hC, &hm.h.adapter_index, &hm.h.obj_index); | ||
3351 | |||
3352 | hm.strv.header.size = sizeof(hm.strv); | ||
3353 | phr->strv.header.size = strv_packet_size - sizeof(phr->h); | ||
3354 | |||
3355 | hpi_send_recv((struct hpi_message *)&hm.h, | ||
3356 | (struct hpi_response *)&phr->h); | ||
3357 | if (phr->h.error == HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL) { | ||
3358 | |||
3359 | HPI_DEBUG_ASSERT(phr->h.specific_error > | ||
3360 | MIN_STRV_PACKET_SIZE | ||
3361 | && phr->h.specific_error < 1000); | ||
3362 | strv_packet_size = phr->h.specific_error; | ||
3363 | } else { | ||
3364 | remaining_attempts = 0; | ||
3365 | if (!phr->h.error) | ||
3366 | hpi_entity_alloc_and_copy(&phr->strv, value); | ||
3367 | } | ||
3368 | |||
3369 | hpi_err = phr->h.error; | ||
3370 | kfree(phr); | ||
3371 | } | ||
3372 | |||
3373 | return hpi_err; | ||
3374 | } | ||
3375 | |||
3376 | u16 hpi_universal_set(const struct hpi_hsubsys *ph_subsys, u32 hC, | ||
3377 | struct hpi_entity *value) | ||
3378 | { | ||
3379 | struct hpi_msg_strv *phm; | ||
3380 | struct hpi_res_strv hr; | ||
3381 | |||
3382 | phm = kmalloc(sizeof(phm->h) + value->header.size, GFP_KERNEL); | ||
3383 | HPI_DEBUG_ASSERT(phm != NULL); | ||
3384 | |||
3385 | hpi_init_message_responseV1(&phm->h, | ||
3386 | sizeof(phm->h) + value->header.size, &hr.h, sizeof(hr), | ||
3387 | HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE); | ||
3388 | u32TOINDEXES(hC, &phm->h.adapter_index, &phm->h.obj_index); | ||
3389 | hr.strv.header.size = sizeof(hr.strv); | ||
3390 | |||
3391 | memcpy(&phm->strv, value, value->header.size); | ||
3392 | hpi_send_recv((struct hpi_message *)&phm->h, | ||
3393 | (struct hpi_response *)&hr.h); | ||
3394 | |||
3395 | return hr.h.error; | ||
3396 | } | ||
3397 | |||
3398 | u16 hpi_entity_alloc_and_pack(const enum e_entity_type type, | ||
3399 | const size_t item_count, const enum e_entity_role role, void *value, | ||
3400 | struct hpi_entity **entity) | ||
3401 | { | ||
3402 | size_t bytes_to_copy, total_size; | ||
3403 | u16 hE = 0; | ||
3404 | *entity = NULL; | ||
3405 | |||
3406 | hE = hpi_entity_check_type(type); | ||
3407 | if (hE) | ||
3408 | return hE; | ||
3409 | |||
3410 | HPI_DEBUG_ASSERT(role > entity_role_null && type < LAST_ENTITY_TYPE); | ||
3411 | |||
3412 | bytes_to_copy = entity_type_to_size[type] * item_count; | ||
3413 | total_size = hpi_entity_header_size(*entity) + bytes_to_copy; | ||
3414 | |||
3415 | HPI_DEBUG_ASSERT(total_size >= hpi_entity_header_size(*entity) | ||
3416 | && total_size < STR_SIZE_FIELD_MAX); | ||
3417 | |||
3418 | *entity = kmalloc(total_size, GFP_KERNEL); | ||
3419 | if (*entity == NULL) | ||
3420 | return HPI_ERROR_MEMORY_ALLOC; | ||
3421 | memcpy((*entity)->value, value, bytes_to_copy); | ||
3422 | (*entity)->header.size = | ||
3423 | hpi_entity_header_size(*entity) + bytes_to_copy; | ||
3424 | (*entity)->header.type = type; | ||
3425 | (*entity)->header.role = role; | ||
3426 | return 0; | ||
3427 | } | ||
3428 | |||
3429 | u16 hpi_entity_copy_value_from(struct hpi_entity *entity, | ||
3430 | enum e_entity_type type, size_t item_count, void *value_dst_p) | ||
3431 | { | ||
3432 | size_t bytes_to_copy; | ||
3433 | |||
3434 | if (entity->header.type != type) | ||
3435 | return HPI_ERROR_ENTITY_TYPE_MISMATCH; | ||
3436 | |||
3437 | if (hpi_entity_item_count(entity) != item_count) | ||
3438 | return HPI_ERROR_ENTITY_ITEM_COUNT; | ||
3439 | |||
3440 | bytes_to_copy = entity_type_to_size[type] * item_count; | ||
3441 | memcpy(value_dst_p, entity->value, bytes_to_copy); | ||
3442 | return 0; | ||
3443 | } | ||
3444 | |||
3445 | u16 hpi_entity_unpack(struct hpi_entity *entity, enum e_entity_type *type, | ||
3446 | size_t *item_count, enum e_entity_role *role, void **value) | ||
3447 | { | ||
3448 | u16 err = 0; | ||
3449 | HPI_DEBUG_ASSERT(entity != NULL); | ||
3450 | |||
3451 | if (type) | ||
3452 | *type = entity->header.type; | ||
3453 | |||
3454 | if (role) | ||
3455 | *role = entity->header.role; | ||
3456 | |||
3457 | if (value) | ||
3458 | *value = entity->value; | ||
3459 | |||
3460 | if (item_count != NULL) { | ||
3461 | if (entity->header.type == entity_type_sequence) { | ||
3462 | void *guard_p = hpi_entity_ptr_to_next(entity); | ||
3463 | struct hpi_entity *next = NULL; | ||
3464 | void *contents = entity->value; | ||
3465 | |||
3466 | *item_count = 0; | ||
3467 | while (contents < guard_p) { | ||
3468 | (*item_count)++; | ||
3469 | err = hpi_entity_get_next(contents, 0, | ||
3470 | guard_p, &next); | ||
3471 | if (next == NULL || err) | ||
3472 | break; | ||
3473 | contents = next; | ||
3474 | } | ||
3475 | } else { | ||
3476 | *item_count = hpi_entity_item_count(entity); | ||
3477 | } | ||
3478 | } | ||
3479 | return err; | ||
3480 | } | ||
3481 | |||
3482 | u16 hpi_gpio_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
3483 | u32 *ph_gpio, u16 *pw_number_input_bits, u16 *pw_number_output_bits) | ||
3484 | { | ||
3485 | struct hpi_message hm; | ||
3486 | struct hpi_response hr; | ||
3487 | hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_OPEN); | ||
3488 | hm.adapter_index = adapter_index; | ||
3489 | |||
3490 | hpi_send_recv(&hm, &hr); | ||
3491 | |||
3492 | if (hr.error == 0) { | ||
3493 | *ph_gpio = | ||
3494 | hpi_indexes_to_handle(HPI_OBJ_GPIO, adapter_index, 0); | ||
3495 | if (pw_number_input_bits) | ||
3496 | *pw_number_input_bits = hr.u.l.number_input_bits; | ||
3497 | if (pw_number_output_bits) | ||
3498 | *pw_number_output_bits = hr.u.l.number_output_bits; | ||
3499 | } else | ||
3500 | *ph_gpio = 0; | ||
3501 | return hr.error; | ||
3502 | } | ||
3503 | |||
3504 | u16 hpi_gpio_read_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio, | ||
3505 | u16 bit_index, u16 *pw_bit_data) | ||
3506 | { | ||
3507 | struct hpi_message hm; | ||
3508 | struct hpi_response hr; | ||
3509 | hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_READ_BIT); | ||
3510 | u32TOINDEX(h_gpio, &hm.adapter_index); | ||
3511 | hm.u.l.bit_index = bit_index; | ||
3512 | |||
3513 | hpi_send_recv(&hm, &hr); | ||
3514 | |||
3515 | *pw_bit_data = hr.u.l.bit_data[0]; | ||
3516 | return hr.error; | ||
3517 | } | ||
3518 | |||
3519 | u16 hpi_gpio_read_all_bits(const struct hpi_hsubsys *ph_subsys, u32 h_gpio, | ||
3520 | u16 aw_all_bit_data[4] | ||
3521 | ) | ||
3522 | { | ||
3523 | struct hpi_message hm; | ||
3524 | struct hpi_response hr; | ||
3525 | hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_READ_ALL); | ||
3526 | u32TOINDEX(h_gpio, &hm.adapter_index); | ||
3527 | |||
3528 | hpi_send_recv(&hm, &hr); | ||
3529 | |||
3530 | if (aw_all_bit_data) { | ||
3531 | aw_all_bit_data[0] = hr.u.l.bit_data[0]; | ||
3532 | aw_all_bit_data[1] = hr.u.l.bit_data[1]; | ||
3533 | aw_all_bit_data[2] = hr.u.l.bit_data[2]; | ||
3534 | aw_all_bit_data[3] = hr.u.l.bit_data[3]; | ||
3535 | } | ||
3536 | return hr.error; | ||
3537 | } | ||
3538 | |||
3539 | u16 hpi_gpio_write_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio, | ||
3540 | u16 bit_index, u16 bit_data) | ||
3541 | { | ||
3542 | struct hpi_message hm; | ||
3543 | struct hpi_response hr; | ||
3544 | hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_WRITE_BIT); | ||
3545 | u32TOINDEX(h_gpio, &hm.adapter_index); | ||
3546 | hm.u.l.bit_index = bit_index; | ||
3547 | hm.u.l.bit_data = bit_data; | ||
3548 | |||
3549 | hpi_send_recv(&hm, &hr); | ||
3550 | |||
3551 | return hr.error; | ||
3552 | } | ||
3553 | |||
3554 | u16 hpi_gpio_write_status(const struct hpi_hsubsys *ph_subsys, u32 h_gpio, | ||
3555 | u16 aw_all_bit_data[4] | ||
3556 | ) | ||
3557 | { | ||
3558 | struct hpi_message hm; | ||
3559 | struct hpi_response hr; | ||
3560 | hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, | ||
3561 | HPI_GPIO_WRITE_STATUS); | ||
3562 | u32TOINDEX(h_gpio, &hm.adapter_index); | ||
3563 | |||
3564 | hpi_send_recv(&hm, &hr); | ||
3565 | |||
3566 | if (aw_all_bit_data) { | ||
3567 | aw_all_bit_data[0] = hr.u.l.bit_data[0]; | ||
3568 | aw_all_bit_data[1] = hr.u.l.bit_data[1]; | ||
3569 | aw_all_bit_data[2] = hr.u.l.bit_data[2]; | ||
3570 | aw_all_bit_data[3] = hr.u.l.bit_data[3]; | ||
3571 | } | ||
3572 | return hr.error; | ||
3573 | } | ||
3574 | |||
3575 | u16 hpi_async_event_open(const struct hpi_hsubsys *ph_subsys, | ||
3576 | u16 adapter_index, u32 *ph_async) | ||
3577 | { | ||
3578 | struct hpi_message hm; | ||
3579 | struct hpi_response hr; | ||
3580 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT, | ||
3581 | HPI_ASYNCEVENT_OPEN); | ||
3582 | hm.adapter_index = adapter_index; | ||
3583 | |||
3584 | hpi_send_recv(&hm, &hr); | ||
3585 | |||
3586 | if (hr.error == 0) | ||
3587 | |||
3588 | *ph_async = | ||
3589 | hpi_indexes_to_handle(HPI_OBJ_ASYNCEVENT, | ||
3590 | adapter_index, 0); | ||
3591 | else | ||
3592 | *ph_async = 0; | ||
3593 | return hr.error; | ||
3594 | |||
3595 | } | ||
3596 | |||
3597 | u16 hpi_async_event_close(const struct hpi_hsubsys *ph_subsys, u32 h_async) | ||
3598 | { | ||
3599 | struct hpi_message hm; | ||
3600 | struct hpi_response hr; | ||
3601 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT, | ||
3602 | HPI_ASYNCEVENT_OPEN); | ||
3603 | u32TOINDEX(h_async, &hm.adapter_index); | ||
3604 | |||
3605 | hpi_send_recv(&hm, &hr); | ||
3606 | |||
3607 | return hr.error; | ||
3608 | } | ||
3609 | |||
3610 | u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async, | ||
3611 | u16 maximum_events, struct hpi_async_event *p_events, | ||
3612 | u16 *pw_number_returned) | ||
3613 | { | ||
3614 | return 0; | ||
3615 | } | ||
3616 | |||
3617 | u16 hpi_async_event_get_count(const struct hpi_hsubsys *ph_subsys, | ||
3618 | u32 h_async, u16 *pw_count) | ||
3619 | { | ||
3620 | struct hpi_message hm; | ||
3621 | struct hpi_response hr; | ||
3622 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT, | ||
3623 | HPI_ASYNCEVENT_GETCOUNT); | ||
3624 | u32TOINDEX(h_async, &hm.adapter_index); | ||
3625 | |||
3626 | hpi_send_recv(&hm, &hr); | ||
3627 | |||
3628 | if (hr.error == 0) | ||
3629 | if (pw_count) | ||
3630 | *pw_count = hr.u.as.u.count.count; | ||
3631 | |||
3632 | return hr.error; | ||
3633 | } | ||
3634 | |||
3635 | u16 hpi_async_event_get(const struct hpi_hsubsys *ph_subsys, u32 h_async, | ||
3636 | u16 maximum_events, struct hpi_async_event *p_events, | ||
3637 | u16 *pw_number_returned) | ||
3638 | { | ||
3639 | struct hpi_message hm; | ||
3640 | struct hpi_response hr; | ||
3641 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT, | ||
3642 | HPI_ASYNCEVENT_GET); | ||
3643 | u32TOINDEX(h_async, &hm.adapter_index); | ||
3644 | |||
3645 | hpi_send_recv(&hm, &hr); | ||
3646 | if (!hr.error) { | ||
3647 | memcpy(p_events, &hr.u.as.u.event, | ||
3648 | sizeof(struct hpi_async_event)); | ||
3649 | *pw_number_returned = 1; | ||
3650 | } | ||
3651 | |||
3652 | return hr.error; | ||
3653 | } | ||
3654 | |||
3655 | u16 hpi_nv_memory_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
3656 | u32 *ph_nv_memory, u16 *pw_size_in_bytes) | ||
3657 | { | ||
3658 | struct hpi_message hm; | ||
3659 | struct hpi_response hr; | ||
3660 | hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY, | ||
3661 | HPI_NVMEMORY_OPEN); | ||
3662 | hm.adapter_index = adapter_index; | ||
3663 | |||
3664 | hpi_send_recv(&hm, &hr); | ||
3665 | |||
3666 | if (hr.error == 0) { | ||
3667 | *ph_nv_memory = | ||
3668 | hpi_indexes_to_handle(HPI_OBJ_NVMEMORY, adapter_index, | ||
3669 | 0); | ||
3670 | if (pw_size_in_bytes) | ||
3671 | *pw_size_in_bytes = hr.u.n.size_in_bytes; | ||
3672 | } else | ||
3673 | *ph_nv_memory = 0; | ||
3674 | return hr.error; | ||
3675 | } | ||
3676 | |||
3677 | u16 hpi_nv_memory_read_byte(const struct hpi_hsubsys *ph_subsys, | ||
3678 | u32 h_nv_memory, u16 index, u16 *pw_data) | ||
3679 | { | ||
3680 | struct hpi_message hm; | ||
3681 | struct hpi_response hr; | ||
3682 | hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY, | ||
3683 | HPI_NVMEMORY_READ_BYTE); | ||
3684 | u32TOINDEX(h_nv_memory, &hm.adapter_index); | ||
3685 | hm.u.n.address = index; | ||
3686 | |||
3687 | hpi_send_recv(&hm, &hr); | ||
3688 | |||
3689 | *pw_data = hr.u.n.data; | ||
3690 | return hr.error; | ||
3691 | } | ||
3692 | |||
3693 | u16 hpi_nv_memory_write_byte(const struct hpi_hsubsys *ph_subsys, | ||
3694 | u32 h_nv_memory, u16 index, u16 data) | ||
3695 | { | ||
3696 | struct hpi_message hm; | ||
3697 | struct hpi_response hr; | ||
3698 | hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY, | ||
3699 | HPI_NVMEMORY_WRITE_BYTE); | ||
3700 | u32TOINDEX(h_nv_memory, &hm.adapter_index); | ||
3701 | hm.u.n.address = index; | ||
3702 | hm.u.n.data = data; | ||
3703 | |||
3704 | hpi_send_recv(&hm, &hr); | ||
3705 | |||
3706 | return hr.error; | ||
3707 | } | ||
3708 | |||
3709 | u16 hpi_profile_open_all(const struct hpi_hsubsys *ph_subsys, | ||
3710 | u16 adapter_index, u16 profile_index, u32 *ph_profile, | ||
3711 | u16 *pw_max_profiles) | ||
3712 | { | ||
3713 | struct hpi_message hm; | ||
3714 | struct hpi_response hr; | ||
3715 | hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE, | ||
3716 | HPI_PROFILE_OPEN_ALL); | ||
3717 | hm.adapter_index = adapter_index; | ||
3718 | hm.obj_index = profile_index; | ||
3719 | hpi_send_recv(&hm, &hr); | ||
3720 | |||
3721 | *pw_max_profiles = hr.u.p.u.o.max_profiles; | ||
3722 | if (hr.error == 0) | ||
3723 | *ph_profile = | ||
3724 | hpi_indexes_to_handle(HPI_OBJ_PROFILE, adapter_index, | ||
3725 | profile_index); | ||
3726 | else | ||
3727 | *ph_profile = 0; | ||
3728 | return hr.error; | ||
3729 | } | ||
3730 | |||
3731 | u16 hpi_profile_get(const struct hpi_hsubsys *ph_subsys, u32 h_profile, | ||
3732 | u16 bin_index, u16 *pw_seconds, u32 *pmicro_seconds, u32 *pcall_count, | ||
3733 | u32 *pmax_micro_seconds, u32 *pmin_micro_seconds) | ||
3734 | { | ||
3735 | struct hpi_message hm; | ||
3736 | struct hpi_response hr; | ||
3737 | hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE, HPI_PROFILE_GET); | ||
3738 | u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index); | ||
3739 | hm.u.p.bin_index = bin_index; | ||
3740 | hpi_send_recv(&hm, &hr); | ||
3741 | if (pw_seconds) | ||
3742 | *pw_seconds = hr.u.p.u.t.seconds; | ||
3743 | if (pmicro_seconds) | ||
3744 | *pmicro_seconds = hr.u.p.u.t.micro_seconds; | ||
3745 | if (pcall_count) | ||
3746 | *pcall_count = hr.u.p.u.t.call_count; | ||
3747 | if (pmax_micro_seconds) | ||
3748 | *pmax_micro_seconds = hr.u.p.u.t.max_micro_seconds; | ||
3749 | if (pmin_micro_seconds) | ||
3750 | *pmin_micro_seconds = hr.u.p.u.t.min_micro_seconds; | ||
3751 | return hr.error; | ||
3752 | } | ||
3753 | |||
3754 | u16 hpi_profile_get_utilization(const struct hpi_hsubsys *ph_subsys, | ||
3755 | u32 h_profile, u32 *putilization) | ||
3756 | { | ||
3757 | struct hpi_message hm; | ||
3758 | struct hpi_response hr; | ||
3759 | hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE, | ||
3760 | HPI_PROFILE_GET_UTILIZATION); | ||
3761 | u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index); | ||
3762 | hpi_send_recv(&hm, &hr); | ||
3763 | if (hr.error) { | ||
3764 | if (putilization) | ||
3765 | *putilization = 0; | ||
3766 | } else { | ||
3767 | if (putilization) | ||
3768 | *putilization = hr.u.p.u.t.call_count; | ||
3769 | } | ||
3770 | return hr.error; | ||
3771 | } | ||
3772 | |||
3773 | u16 hpi_profile_get_name(const struct hpi_hsubsys *ph_subsys, u32 h_profile, | ||
3774 | u16 bin_index, char *sz_name, u16 name_length) | ||
3775 | { | ||
3776 | struct hpi_message hm; | ||
3777 | struct hpi_response hr; | ||
3778 | hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE, | ||
3779 | HPI_PROFILE_GET_NAME); | ||
3780 | u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index); | ||
3781 | hm.u.p.bin_index = bin_index; | ||
3782 | hpi_send_recv(&hm, &hr); | ||
3783 | if (hr.error) { | ||
3784 | if (sz_name) | ||
3785 | strcpy(sz_name, "??"); | ||
3786 | } else { | ||
3787 | if (sz_name) | ||
3788 | memcpy(sz_name, (char *)hr.u.p.u.n.sz_name, | ||
3789 | name_length); | ||
3790 | } | ||
3791 | return hr.error; | ||
3792 | } | ||
3793 | |||
3794 | u16 hpi_profile_start_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile) | ||
3795 | { | ||
3796 | struct hpi_message hm; | ||
3797 | struct hpi_response hr; | ||
3798 | hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE, | ||
3799 | HPI_PROFILE_START_ALL); | ||
3800 | u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index); | ||
3801 | hpi_send_recv(&hm, &hr); | ||
3802 | |||
3803 | return hr.error; | ||
3804 | } | ||
3805 | |||
3806 | u16 hpi_profile_stop_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile) | ||
3807 | { | ||
3808 | struct hpi_message hm; | ||
3809 | struct hpi_response hr; | ||
3810 | hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE, | ||
3811 | HPI_PROFILE_STOP_ALL); | ||
3812 | u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index); | ||
3813 | hpi_send_recv(&hm, &hr); | ||
3814 | |||
3815 | return hr.error; | ||
3816 | } | ||
3817 | |||
3818 | u16 hpi_watchdog_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index, | ||
3819 | u32 *ph_watchdog) | ||
3820 | { | ||
3821 | struct hpi_message hm; | ||
3822 | struct hpi_response hr; | ||
3823 | hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG, | ||
3824 | HPI_WATCHDOG_OPEN); | ||
3825 | hm.adapter_index = adapter_index; | ||
3826 | |||
3827 | hpi_send_recv(&hm, &hr); | ||
3828 | |||
3829 | if (hr.error == 0) | ||
3830 | *ph_watchdog = | ||
3831 | hpi_indexes_to_handle(HPI_OBJ_WATCHDOG, adapter_index, | ||
3832 | 0); | ||
3833 | else | ||
3834 | *ph_watchdog = 0; | ||
3835 | return hr.error; | ||
3836 | } | ||
3837 | |||
3838 | u16 hpi_watchdog_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog, | ||
3839 | u32 time_millisec) | ||
3840 | { | ||
3841 | struct hpi_message hm; | ||
3842 | struct hpi_response hr; | ||
3843 | hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG, | ||
3844 | HPI_WATCHDOG_SET_TIME); | ||
3845 | u32TOINDEX(h_watchdog, &hm.adapter_index); | ||
3846 | hm.u.w.time_ms = time_millisec; | ||
3847 | |||
3848 | hpi_send_recv(&hm, &hr); | ||
3849 | |||
3850 | return hr.error; | ||
3851 | } | ||
3852 | |||
3853 | u16 hpi_watchdog_ping(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog) | ||
3854 | { | ||
3855 | struct hpi_message hm; | ||
3856 | struct hpi_response hr; | ||
3857 | hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG, | ||
3858 | HPI_WATCHDOG_PING); | ||
3859 | u32TOINDEX(h_watchdog, &hm.adapter_index); | ||
3860 | |||
3861 | hpi_send_recv(&hm, &hr); | ||
3862 | |||
3863 | return hr.error; | ||
3864 | } | ||
diff --git a/sound/pci/asihpi/hpimsginit.c b/sound/pci/asihpi/hpimsginit.c new file mode 100644 index 00000000000..8e1d099ed7e --- /dev/null +++ b/sound/pci/asihpi/hpimsginit.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Hardware Programming Interface (HPI) Utility functions. | ||
20 | |||
21 | (C) Copyright AudioScience Inc. 2007 | ||
22 | *******************************************************************************/ | ||
23 | |||
24 | #include "hpi_internal.h" | ||
25 | #include "hpimsginit.h" | ||
26 | |||
27 | /* The actual message size for each object type */ | ||
28 | static u16 msg_size[HPI_OBJ_MAXINDEX + 1] = HPI_MESSAGE_SIZE_BY_OBJECT; | ||
29 | /* The actual response size for each object type */ | ||
30 | static u16 res_size[HPI_OBJ_MAXINDEX + 1] = HPI_RESPONSE_SIZE_BY_OBJECT; | ||
31 | /* Flag to enable alternate message type for SSX2 bypass. */ | ||
32 | static u16 gwSSX2_bypass; | ||
33 | |||
34 | /** \internal | ||
35 | * Used by ASIO driver to disable SSX2 for a single process | ||
36 | * \param phSubSys Pointer to HPI subsystem handle. | ||
37 | * \param wBypass New bypass setting 0 = off, nonzero = on | ||
38 | * \return Previous bypass setting. | ||
39 | */ | ||
40 | u16 hpi_subsys_ssx2_bypass(const struct hpi_hsubsys *ph_subsys, u16 bypass) | ||
41 | { | ||
42 | u16 old_value = gwSSX2_bypass; | ||
43 | |||
44 | gwSSX2_bypass = bypass; | ||
45 | |||
46 | return old_value; | ||
47 | } | ||
48 | |||
49 | /** \internal | ||
50 | * initialize the HPI message structure | ||
51 | */ | ||
52 | static void hpi_init_message(struct hpi_message *phm, u16 object, | ||
53 | u16 function) | ||
54 | { | ||
55 | memset(phm, 0, sizeof(*phm)); | ||
56 | if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) | ||
57 | phm->size = msg_size[object]; | ||
58 | else | ||
59 | phm->size = sizeof(*phm); | ||
60 | |||
61 | if (gwSSX2_bypass) | ||
62 | phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE; | ||
63 | else | ||
64 | phm->type = HPI_TYPE_MESSAGE; | ||
65 | phm->object = object; | ||
66 | phm->function = function; | ||
67 | phm->version = 0; | ||
68 | /* Expect adapter index to be set by caller */ | ||
69 | } | ||
70 | |||
71 | /** \internal | ||
72 | * initialize the HPI response structure | ||
73 | */ | ||
74 | void hpi_init_response(struct hpi_response *phr, u16 object, u16 function, | ||
75 | u16 error) | ||
76 | { | ||
77 | memset(phr, 0, sizeof(*phr)); | ||
78 | phr->type = HPI_TYPE_RESPONSE; | ||
79 | if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) | ||
80 | phr->size = res_size[object]; | ||
81 | else | ||
82 | phr->size = sizeof(*phr); | ||
83 | phr->object = object; | ||
84 | phr->function = function; | ||
85 | phr->error = error; | ||
86 | phr->specific_error = 0; | ||
87 | phr->version = 0; | ||
88 | } | ||
89 | |||
90 | void hpi_init_message_response(struct hpi_message *phm, | ||
91 | struct hpi_response *phr, u16 object, u16 function) | ||
92 | { | ||
93 | hpi_init_message(phm, object, function); | ||
94 | /* default error return if the response is | ||
95 | not filled in by the callee */ | ||
96 | hpi_init_response(phr, object, function, | ||
97 | HPI_ERROR_PROCESSING_MESSAGE); | ||
98 | } | ||
99 | |||
100 | static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size, | ||
101 | u16 object, u16 function) | ||
102 | { | ||
103 | memset(phm, 0, sizeof(*phm)); | ||
104 | if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) { | ||
105 | phm->size = size; | ||
106 | phm->type = HPI_TYPE_MESSAGE; | ||
107 | phm->object = object; | ||
108 | phm->function = function; | ||
109 | phm->version = 1; | ||
110 | /* Expect adapter index to be set by caller */ | ||
111 | } | ||
112 | } | ||
113 | |||
114 | void hpi_init_responseV1(struct hpi_response_header *phr, u16 size, | ||
115 | u16 object, u16 function) | ||
116 | { | ||
117 | memset(phr, 0, sizeof(*phr)); | ||
118 | phr->size = size; | ||
119 | phr->version = 1; | ||
120 | phr->type = HPI_TYPE_RESPONSE; | ||
121 | phr->error = HPI_ERROR_PROCESSING_MESSAGE; | ||
122 | } | ||
123 | |||
124 | void hpi_init_message_responseV1(struct hpi_message_header *phm, u16 msg_size, | ||
125 | struct hpi_response_header *phr, u16 res_size, u16 object, | ||
126 | u16 function) | ||
127 | { | ||
128 | hpi_init_messageV1(phm, msg_size, object, function); | ||
129 | hpi_init_responseV1(phr, res_size, object, function); | ||
130 | } | ||
diff --git a/sound/pci/asihpi/hpimsginit.h b/sound/pci/asihpi/hpimsginit.h new file mode 100644 index 00000000000..864ad020c9b --- /dev/null +++ b/sound/pci/asihpi/hpimsginit.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Hardware Programming Interface (HPI) Utility functions | ||
20 | |||
21 | (C) Copyright AudioScience Inc. 2007 | ||
22 | *******************************************************************************/ | ||
23 | /* Initialise response headers, or msg/response pairs. | ||
24 | Note that it is valid to just init a response e.g. when a lower level is preparing | ||
25 | a response to a message. | ||
26 | However, when sending a message, a matching response buffer always must be prepared | ||
27 | */ | ||
28 | |||
29 | void hpi_init_response(struct hpi_response *phr, u16 object, u16 function, | ||
30 | u16 error); | ||
31 | |||
32 | void hpi_init_message_response(struct hpi_message *phm, | ||
33 | struct hpi_response *phr, u16 object, u16 function); | ||
34 | |||
35 | void hpi_init_responseV1(struct hpi_response_header *phr, u16 size, | ||
36 | u16 object, u16 function); | ||
37 | |||
38 | void hpi_init_message_responseV1(struct hpi_message_header *phm, u16 msg_size, | ||
39 | struct hpi_response_header *phr, u16 res_size, u16 object, | ||
40 | u16 function); | ||
diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c new file mode 100644 index 00000000000..2ee90dc3d89 --- /dev/null +++ b/sound/pci/asihpi/hpimsgx.c | |||
@@ -0,0 +1,907 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Extended Message Function With Response Cacheing | ||
20 | |||
21 | (C) Copyright AudioScience Inc. 2002 | ||
22 | *****************************************************************************/ | ||
23 | #define SOURCEFILE_NAME "hpimsgx.c" | ||
24 | #include "hpi_internal.h" | ||
25 | #include "hpimsginit.h" | ||
26 | #include "hpimsgx.h" | ||
27 | #include "hpidebug.h" | ||
28 | |||
29 | static struct pci_device_id asihpi_pci_tbl[] = { | ||
30 | #include "hpipcida.h" | ||
31 | }; | ||
32 | |||
33 | static struct hpios_spinlock msgx_lock; | ||
34 | |||
35 | static hpi_handler_func *hpi_entry_points[HPI_MAX_ADAPTERS]; | ||
36 | |||
37 | static hpi_handler_func *hpi_lookup_entry_point_function(const struct hpi_pci | ||
38 | *pci_info) | ||
39 | { | ||
40 | |||
41 | int i; | ||
42 | |||
43 | for (i = 0; asihpi_pci_tbl[i].vendor != 0; i++) { | ||
44 | if (asihpi_pci_tbl[i].vendor != PCI_ANY_ID | ||
45 | && asihpi_pci_tbl[i].vendor != pci_info->vendor_id) | ||
46 | continue; | ||
47 | if (asihpi_pci_tbl[i].device != PCI_ANY_ID | ||
48 | && asihpi_pci_tbl[i].device != pci_info->device_id) | ||
49 | continue; | ||
50 | if (asihpi_pci_tbl[i].subvendor != PCI_ANY_ID | ||
51 | && asihpi_pci_tbl[i].subvendor != | ||
52 | pci_info->subsys_vendor_id) | ||
53 | continue; | ||
54 | if (asihpi_pci_tbl[i].subdevice != PCI_ANY_ID | ||
55 | && asihpi_pci_tbl[i].subdevice != | ||
56 | pci_info->subsys_device_id) | ||
57 | continue; | ||
58 | |||
59 | HPI_DEBUG_LOG(DEBUG, " %x,%lu\n", i, | ||
60 | asihpi_pci_tbl[i].driver_data); | ||
61 | return (hpi_handler_func *) asihpi_pci_tbl[i].driver_data; | ||
62 | } | ||
63 | |||
64 | return NULL; | ||
65 | } | ||
66 | |||
67 | static inline void hw_entry_point(struct hpi_message *phm, | ||
68 | struct hpi_response *phr) | ||
69 | { | ||
70 | |||
71 | hpi_handler_func *ep; | ||
72 | |||
73 | if (phm->adapter_index < HPI_MAX_ADAPTERS) { | ||
74 | ep = (hpi_handler_func *) hpi_entry_points[phm-> | ||
75 | adapter_index]; | ||
76 | if (ep) { | ||
77 | HPI_DEBUG_MESSAGE(DEBUG, phm); | ||
78 | ep(phm, phr); | ||
79 | HPI_DEBUG_RESPONSE(phr); | ||
80 | return; | ||
81 | } | ||
82 | } | ||
83 | hpi_init_response(phr, phm->object, phm->function, | ||
84 | HPI_ERROR_PROCESSING_MESSAGE); | ||
85 | } | ||
86 | |||
87 | static void adapter_open(struct hpi_message *phm, struct hpi_response *phr); | ||
88 | static void adapter_close(struct hpi_message *phm, struct hpi_response *phr); | ||
89 | |||
90 | static void mixer_open(struct hpi_message *phm, struct hpi_response *phr); | ||
91 | static void mixer_close(struct hpi_message *phm, struct hpi_response *phr); | ||
92 | |||
93 | static void outstream_open(struct hpi_message *phm, struct hpi_response *phr, | ||
94 | void *h_owner); | ||
95 | static void outstream_close(struct hpi_message *phm, struct hpi_response *phr, | ||
96 | void *h_owner); | ||
97 | static void instream_open(struct hpi_message *phm, struct hpi_response *phr, | ||
98 | void *h_owner); | ||
99 | static void instream_close(struct hpi_message *phm, struct hpi_response *phr, | ||
100 | void *h_owner); | ||
101 | |||
102 | static void HPIMSGX__reset(u16 adapter_index); | ||
103 | static u16 HPIMSGX__init(struct hpi_message *phm, struct hpi_response *phr); | ||
104 | static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner); | ||
105 | |||
106 | #ifndef DISABLE_PRAGMA_PACK1 | ||
107 | #pragma pack(push, 1) | ||
108 | #endif | ||
109 | |||
110 | struct hpi_subsys_response { | ||
111 | struct hpi_response_header h; | ||
112 | struct hpi_subsys_res s; | ||
113 | }; | ||
114 | |||
115 | struct hpi_adapter_response { | ||
116 | struct hpi_response_header h; | ||
117 | struct hpi_adapter_res a; | ||
118 | }; | ||
119 | |||
120 | struct hpi_mixer_response { | ||
121 | struct hpi_response_header h; | ||
122 | struct hpi_mixer_res m; | ||
123 | }; | ||
124 | |||
125 | struct hpi_stream_response { | ||
126 | struct hpi_response_header h; | ||
127 | struct hpi_stream_res d; | ||
128 | }; | ||
129 | |||
130 | struct adapter_info { | ||
131 | u16 type; | ||
132 | u16 num_instreams; | ||
133 | u16 num_outstreams; | ||
134 | }; | ||
135 | |||
136 | struct asi_open_state { | ||
137 | int open_flag; | ||
138 | void *h_owner; | ||
139 | }; | ||
140 | |||
141 | #ifndef DISABLE_PRAGMA_PACK1 | ||
142 | #pragma pack(pop) | ||
143 | #endif | ||
144 | |||
145 | /* Globals */ | ||
146 | static struct hpi_adapter_response rESP_HPI_ADAPTER_OPEN[HPI_MAX_ADAPTERS]; | ||
147 | |||
148 | static struct hpi_stream_response | ||
149 | rESP_HPI_OSTREAM_OPEN[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; | ||
150 | |||
151 | static struct hpi_stream_response | ||
152 | rESP_HPI_ISTREAM_OPEN[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; | ||
153 | |||
154 | static struct hpi_mixer_response rESP_HPI_MIXER_OPEN[HPI_MAX_ADAPTERS]; | ||
155 | |||
156 | static struct hpi_subsys_response gRESP_HPI_SUBSYS_FIND_ADAPTERS; | ||
157 | |||
158 | static struct adapter_info aDAPTER_INFO[HPI_MAX_ADAPTERS]; | ||
159 | |||
160 | /* use these to keep track of opens from user mode apps/DLLs */ | ||
161 | static struct asi_open_state | ||
162 | outstream_user_open[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; | ||
163 | |||
164 | static struct asi_open_state | ||
165 | instream_user_open[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; | ||
166 | |||
167 | static void subsys_message(struct hpi_message *phm, struct hpi_response *phr, | ||
168 | void *h_owner) | ||
169 | { | ||
170 | switch (phm->function) { | ||
171 | case HPI_SUBSYS_GET_VERSION: | ||
172 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, | ||
173 | HPI_SUBSYS_GET_VERSION, 0); | ||
174 | phr->u.s.version = HPI_VER >> 8; /* return major.minor */ | ||
175 | phr->u.s.data = HPI_VER; /* return major.minor.release */ | ||
176 | break; | ||
177 | case HPI_SUBSYS_OPEN: | ||
178 | /*do not propagate the message down the chain */ | ||
179 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_OPEN, 0); | ||
180 | break; | ||
181 | case HPI_SUBSYS_CLOSE: | ||
182 | /*do not propagate the message down the chain */ | ||
183 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CLOSE, | ||
184 | 0); | ||
185 | HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner); | ||
186 | break; | ||
187 | case HPI_SUBSYS_DRIVER_LOAD: | ||
188 | /* Initialize this module's internal state */ | ||
189 | hpios_msgxlock_init(&msgx_lock); | ||
190 | memset(&hpi_entry_points, 0, sizeof(hpi_entry_points)); | ||
191 | hpios_locked_mem_init(); | ||
192 | /* Init subsys_findadapters response to no-adapters */ | ||
193 | HPIMSGX__reset(HPIMSGX_ALLADAPTERS); | ||
194 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, | ||
195 | HPI_SUBSYS_DRIVER_LOAD, 0); | ||
196 | /* individual HPIs dont implement driver load */ | ||
197 | HPI_COMMON(phm, phr); | ||
198 | break; | ||
199 | case HPI_SUBSYS_DRIVER_UNLOAD: | ||
200 | HPI_COMMON(phm, phr); | ||
201 | HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner); | ||
202 | hpios_locked_mem_free_all(); | ||
203 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, | ||
204 | HPI_SUBSYS_DRIVER_UNLOAD, 0); | ||
205 | return; | ||
206 | |||
207 | case HPI_SUBSYS_GET_INFO: | ||
208 | HPI_COMMON(phm, phr); | ||
209 | break; | ||
210 | |||
211 | case HPI_SUBSYS_FIND_ADAPTERS: | ||
212 | memcpy(phr, &gRESP_HPI_SUBSYS_FIND_ADAPTERS, | ||
213 | sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS)); | ||
214 | break; | ||
215 | case HPI_SUBSYS_GET_NUM_ADAPTERS: | ||
216 | memcpy(phr, &gRESP_HPI_SUBSYS_FIND_ADAPTERS, | ||
217 | sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS)); | ||
218 | phr->function = HPI_SUBSYS_GET_NUM_ADAPTERS; | ||
219 | break; | ||
220 | case HPI_SUBSYS_GET_ADAPTER: | ||
221 | { | ||
222 | int count = phm->adapter_index; | ||
223 | int index = 0; | ||
224 | hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, | ||
225 | HPI_SUBSYS_GET_ADAPTER, 0); | ||
226 | |||
227 | /* This is complicated by the fact that we want to | ||
228 | * "skip" 0's in the adapter list. | ||
229 | * First, make sure we are pointing to a | ||
230 | * non-zero adapter type. | ||
231 | */ | ||
232 | while (gRESP_HPI_SUBSYS_FIND_ADAPTERS. | ||
233 | s.aw_adapter_list[index] == 0) { | ||
234 | index++; | ||
235 | if (index >= HPI_MAX_ADAPTERS) | ||
236 | break; | ||
237 | } | ||
238 | while (count) { | ||
239 | /* move on to the next adapter */ | ||
240 | index++; | ||
241 | if (index >= HPI_MAX_ADAPTERS) | ||
242 | break; | ||
243 | while (gRESP_HPI_SUBSYS_FIND_ADAPTERS. | ||
244 | s.aw_adapter_list[index] == 0) { | ||
245 | index++; | ||
246 | if (index >= HPI_MAX_ADAPTERS) | ||
247 | break; | ||
248 | } | ||
249 | count--; | ||
250 | } | ||
251 | |||
252 | if (index < HPI_MAX_ADAPTERS) { | ||
253 | phr->u.s.adapter_index = (u16)index; | ||
254 | phr->u.s.aw_adapter_list[0] = | ||
255 | gRESP_HPI_SUBSYS_FIND_ADAPTERS. | ||
256 | s.aw_adapter_list[index]; | ||
257 | } else { | ||
258 | phr->u.s.adapter_index = 0; | ||
259 | phr->u.s.aw_adapter_list[0] = 0; | ||
260 | phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER; | ||
261 | } | ||
262 | break; | ||
263 | } | ||
264 | case HPI_SUBSYS_CREATE_ADAPTER: | ||
265 | HPIMSGX__init(phm, phr); | ||
266 | break; | ||
267 | case HPI_SUBSYS_DELETE_ADAPTER: | ||
268 | HPIMSGX__cleanup(phm->adapter_index, h_owner); | ||
269 | { | ||
270 | struct hpi_message hm; | ||
271 | struct hpi_response hr; | ||
272 | /* call to HPI_ADAPTER_CLOSE */ | ||
273 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
274 | HPI_ADAPTER_CLOSE); | ||
275 | hm.adapter_index = phm->adapter_index; | ||
276 | hw_entry_point(&hm, &hr); | ||
277 | } | ||
278 | hw_entry_point(phm, phr); | ||
279 | gRESP_HPI_SUBSYS_FIND_ADAPTERS.s. | ||
280 | aw_adapter_list[phm->adapter_index] | ||
281 | = 0; | ||
282 | hpi_entry_points[phm->adapter_index] = NULL; | ||
283 | break; | ||
284 | default: | ||
285 | hw_entry_point(phm, phr); | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | static void adapter_message(struct hpi_message *phm, struct hpi_response *phr, | ||
291 | void *h_owner) | ||
292 | { | ||
293 | switch (phm->function) { | ||
294 | case HPI_ADAPTER_OPEN: | ||
295 | adapter_open(phm, phr); | ||
296 | break; | ||
297 | case HPI_ADAPTER_CLOSE: | ||
298 | adapter_close(phm, phr); | ||
299 | break; | ||
300 | default: | ||
301 | hw_entry_point(phm, phr); | ||
302 | break; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static void mixer_message(struct hpi_message *phm, struct hpi_response *phr) | ||
307 | { | ||
308 | switch (phm->function) { | ||
309 | case HPI_MIXER_OPEN: | ||
310 | mixer_open(phm, phr); | ||
311 | break; | ||
312 | case HPI_MIXER_CLOSE: | ||
313 | mixer_close(phm, phr); | ||
314 | break; | ||
315 | default: | ||
316 | hw_entry_point(phm, phr); | ||
317 | break; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | static void outstream_message(struct hpi_message *phm, | ||
322 | struct hpi_response *phr, void *h_owner) | ||
323 | { | ||
324 | if (phm->obj_index >= aDAPTER_INFO[phm->adapter_index].num_outstreams) { | ||
325 | hpi_init_response(phr, HPI_OBJ_OSTREAM, phm->function, | ||
326 | HPI_ERROR_INVALID_OBJ_INDEX); | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | switch (phm->function) { | ||
331 | case HPI_OSTREAM_OPEN: | ||
332 | outstream_open(phm, phr, h_owner); | ||
333 | break; | ||
334 | case HPI_OSTREAM_CLOSE: | ||
335 | outstream_close(phm, phr, h_owner); | ||
336 | break; | ||
337 | default: | ||
338 | hw_entry_point(phm, phr); | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static void instream_message(struct hpi_message *phm, | ||
344 | struct hpi_response *phr, void *h_owner) | ||
345 | { | ||
346 | if (phm->obj_index >= aDAPTER_INFO[phm->adapter_index].num_instreams) { | ||
347 | hpi_init_response(phr, HPI_OBJ_ISTREAM, phm->function, | ||
348 | HPI_ERROR_INVALID_OBJ_INDEX); | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | switch (phm->function) { | ||
353 | case HPI_ISTREAM_OPEN: | ||
354 | instream_open(phm, phr, h_owner); | ||
355 | break; | ||
356 | case HPI_ISTREAM_CLOSE: | ||
357 | instream_close(phm, phr, h_owner); | ||
358 | break; | ||
359 | default: | ||
360 | hw_entry_point(phm, phr); | ||
361 | break; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | /* NOTE: HPI_Message() must be defined in the driver as a wrapper for | ||
366 | * HPI_MessageEx so that functions in hpifunc.c compile. | ||
367 | */ | ||
368 | void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr, | ||
369 | void *h_owner) | ||
370 | { | ||
371 | HPI_DEBUG_MESSAGE(DEBUG, phm); | ||
372 | |||
373 | if (phm->type != HPI_TYPE_MESSAGE) { | ||
374 | hpi_init_response(phr, phm->object, phm->function, | ||
375 | HPI_ERROR_INVALID_TYPE); | ||
376 | return; | ||
377 | } | ||
378 | |||
379 | if (phm->adapter_index >= HPI_MAX_ADAPTERS | ||
380 | && phm->adapter_index != HPIMSGX_ALLADAPTERS) { | ||
381 | hpi_init_response(phr, phm->object, phm->function, | ||
382 | HPI_ERROR_BAD_ADAPTER_NUMBER); | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | switch (phm->object) { | ||
387 | case HPI_OBJ_SUBSYSTEM: | ||
388 | subsys_message(phm, phr, h_owner); | ||
389 | break; | ||
390 | |||
391 | case HPI_OBJ_ADAPTER: | ||
392 | adapter_message(phm, phr, h_owner); | ||
393 | break; | ||
394 | |||
395 | case HPI_OBJ_MIXER: | ||
396 | mixer_message(phm, phr); | ||
397 | break; | ||
398 | |||
399 | case HPI_OBJ_OSTREAM: | ||
400 | outstream_message(phm, phr, h_owner); | ||
401 | break; | ||
402 | |||
403 | case HPI_OBJ_ISTREAM: | ||
404 | instream_message(phm, phr, h_owner); | ||
405 | break; | ||
406 | |||
407 | default: | ||
408 | hw_entry_point(phm, phr); | ||
409 | break; | ||
410 | } | ||
411 | HPI_DEBUG_RESPONSE(phr); | ||
412 | #if 1 | ||
413 | if (phr->error >= HPI_ERROR_BACKEND_BASE) { | ||
414 | void *ep = NULL; | ||
415 | char *ep_name; | ||
416 | |||
417 | HPI_DEBUG_MESSAGE(ERROR, phm); | ||
418 | |||
419 | if (phm->adapter_index < HPI_MAX_ADAPTERS) | ||
420 | ep = hpi_entry_points[phm->adapter_index]; | ||
421 | |||
422 | /* Don't need this? Have adapter index in debug info | ||
423 | Know at driver load time index->backend mapping */ | ||
424 | if (ep == HPI_6000) | ||
425 | ep_name = "HPI_6000"; | ||
426 | else if (ep == HPI_6205) | ||
427 | ep_name = "HPI_6205"; | ||
428 | else | ||
429 | ep_name = "unknown"; | ||
430 | |||
431 | HPI_DEBUG_LOG(ERROR, "HPI %s response - error# %d\n", ep_name, | ||
432 | phr->error); | ||
433 | |||
434 | if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) | ||
435 | hpi_debug_data((u16 *)phm, | ||
436 | sizeof(*phm) / sizeof(u16)); | ||
437 | } | ||
438 | #endif | ||
439 | } | ||
440 | |||
441 | static void adapter_open(struct hpi_message *phm, struct hpi_response *phr) | ||
442 | { | ||
443 | HPI_DEBUG_LOG(VERBOSE, "adapter_open\n"); | ||
444 | memcpy(phr, &rESP_HPI_ADAPTER_OPEN[phm->adapter_index], | ||
445 | sizeof(rESP_HPI_ADAPTER_OPEN[0])); | ||
446 | } | ||
447 | |||
448 | static void adapter_close(struct hpi_message *phm, struct hpi_response *phr) | ||
449 | { | ||
450 | HPI_DEBUG_LOG(VERBOSE, "adapter_close\n"); | ||
451 | hpi_init_response(phr, HPI_OBJ_ADAPTER, HPI_ADAPTER_CLOSE, 0); | ||
452 | } | ||
453 | |||
454 | static void mixer_open(struct hpi_message *phm, struct hpi_response *phr) | ||
455 | { | ||
456 | memcpy(phr, &rESP_HPI_MIXER_OPEN[phm->adapter_index], | ||
457 | sizeof(rESP_HPI_MIXER_OPEN[0])); | ||
458 | } | ||
459 | |||
460 | static void mixer_close(struct hpi_message *phm, struct hpi_response *phr) | ||
461 | { | ||
462 | hpi_init_response(phr, HPI_OBJ_MIXER, HPI_MIXER_CLOSE, 0); | ||
463 | } | ||
464 | |||
465 | static void instream_open(struct hpi_message *phm, struct hpi_response *phr, | ||
466 | void *h_owner) | ||
467 | { | ||
468 | |||
469 | struct hpi_message hm; | ||
470 | struct hpi_response hr; | ||
471 | |||
472 | hpi_init_response(phr, HPI_OBJ_ISTREAM, HPI_ISTREAM_OPEN, 0); | ||
473 | |||
474 | hpios_msgxlock_lock(&msgx_lock); | ||
475 | |||
476 | if (instream_user_open[phm->adapter_index][phm->obj_index].open_flag) | ||
477 | phr->error = HPI_ERROR_OBJ_ALREADY_OPEN; | ||
478 | else if (rESP_HPI_ISTREAM_OPEN[phm->adapter_index] | ||
479 | [phm->obj_index].h.error) | ||
480 | memcpy(phr, | ||
481 | &rESP_HPI_ISTREAM_OPEN[phm->adapter_index][phm-> | ||
482 | obj_index], | ||
483 | sizeof(rESP_HPI_ISTREAM_OPEN[0][0])); | ||
484 | else { | ||
485 | instream_user_open[phm->adapter_index][phm-> | ||
486 | obj_index].open_flag = 1; | ||
487 | hpios_msgxlock_un_lock(&msgx_lock); | ||
488 | |||
489 | /* issue a reset */ | ||
490 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
491 | HPI_ISTREAM_RESET); | ||
492 | hm.adapter_index = phm->adapter_index; | ||
493 | hm.obj_index = phm->obj_index; | ||
494 | hw_entry_point(&hm, &hr); | ||
495 | |||
496 | hpios_msgxlock_lock(&msgx_lock); | ||
497 | if (hr.error) { | ||
498 | instream_user_open[phm->adapter_index][phm-> | ||
499 | obj_index].open_flag = 0; | ||
500 | phr->error = hr.error; | ||
501 | } else { | ||
502 | instream_user_open[phm->adapter_index][phm-> | ||
503 | obj_index].open_flag = 1; | ||
504 | instream_user_open[phm->adapter_index][phm-> | ||
505 | obj_index].h_owner = h_owner; | ||
506 | memcpy(phr, | ||
507 | &rESP_HPI_ISTREAM_OPEN[phm->adapter_index] | ||
508 | [phm->obj_index], | ||
509 | sizeof(rESP_HPI_ISTREAM_OPEN[0][0])); | ||
510 | } | ||
511 | } | ||
512 | hpios_msgxlock_un_lock(&msgx_lock); | ||
513 | } | ||
514 | |||
515 | static void instream_close(struct hpi_message *phm, struct hpi_response *phr, | ||
516 | void *h_owner) | ||
517 | { | ||
518 | |||
519 | struct hpi_message hm; | ||
520 | struct hpi_response hr; | ||
521 | |||
522 | hpi_init_response(phr, HPI_OBJ_ISTREAM, HPI_ISTREAM_CLOSE, 0); | ||
523 | |||
524 | hpios_msgxlock_lock(&msgx_lock); | ||
525 | if (h_owner == | ||
526 | instream_user_open[phm->adapter_index][phm-> | ||
527 | obj_index].h_owner) { | ||
528 | /* HPI_DEBUG_LOG(INFO,"closing adapter %d " | ||
529 | "instream %d owned by %p\n", | ||
530 | phm->wAdapterIndex, phm->wObjIndex, hOwner); */ | ||
531 | instream_user_open[phm->adapter_index][phm-> | ||
532 | obj_index].h_owner = NULL; | ||
533 | hpios_msgxlock_un_lock(&msgx_lock); | ||
534 | /* issue a reset */ | ||
535 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
536 | HPI_ISTREAM_RESET); | ||
537 | hm.adapter_index = phm->adapter_index; | ||
538 | hm.obj_index = phm->obj_index; | ||
539 | hw_entry_point(&hm, &hr); | ||
540 | hpios_msgxlock_lock(&msgx_lock); | ||
541 | if (hr.error) { | ||
542 | instream_user_open[phm->adapter_index][phm-> | ||
543 | obj_index].h_owner = h_owner; | ||
544 | phr->error = hr.error; | ||
545 | } else { | ||
546 | instream_user_open[phm->adapter_index][phm-> | ||
547 | obj_index].open_flag = 0; | ||
548 | instream_user_open[phm->adapter_index][phm-> | ||
549 | obj_index].h_owner = NULL; | ||
550 | } | ||
551 | } else { | ||
552 | HPI_DEBUG_LOG(WARNING, | ||
553 | "%p trying to close %d instream %d owned by %p\n", | ||
554 | h_owner, phm->adapter_index, phm->obj_index, | ||
555 | instream_user_open[phm->adapter_index][phm-> | ||
556 | obj_index].h_owner); | ||
557 | phr->error = HPI_ERROR_OBJ_NOT_OPEN; | ||
558 | } | ||
559 | hpios_msgxlock_un_lock(&msgx_lock); | ||
560 | } | ||
561 | |||
562 | static void outstream_open(struct hpi_message *phm, struct hpi_response *phr, | ||
563 | void *h_owner) | ||
564 | { | ||
565 | |||
566 | struct hpi_message hm; | ||
567 | struct hpi_response hr; | ||
568 | |||
569 | hpi_init_response(phr, HPI_OBJ_OSTREAM, HPI_OSTREAM_OPEN, 0); | ||
570 | |||
571 | hpios_msgxlock_lock(&msgx_lock); | ||
572 | |||
573 | if (outstream_user_open[phm->adapter_index][phm->obj_index].open_flag) | ||
574 | phr->error = HPI_ERROR_OBJ_ALREADY_OPEN; | ||
575 | else if (rESP_HPI_OSTREAM_OPEN[phm->adapter_index] | ||
576 | [phm->obj_index].h.error) | ||
577 | memcpy(phr, | ||
578 | &rESP_HPI_OSTREAM_OPEN[phm->adapter_index][phm-> | ||
579 | obj_index], | ||
580 | sizeof(rESP_HPI_OSTREAM_OPEN[0][0])); | ||
581 | else { | ||
582 | outstream_user_open[phm->adapter_index][phm-> | ||
583 | obj_index].open_flag = 1; | ||
584 | hpios_msgxlock_un_lock(&msgx_lock); | ||
585 | |||
586 | /* issue a reset */ | ||
587 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
588 | HPI_OSTREAM_RESET); | ||
589 | hm.adapter_index = phm->adapter_index; | ||
590 | hm.obj_index = phm->obj_index; | ||
591 | hw_entry_point(&hm, &hr); | ||
592 | |||
593 | hpios_msgxlock_lock(&msgx_lock); | ||
594 | if (hr.error) { | ||
595 | outstream_user_open[phm->adapter_index][phm-> | ||
596 | obj_index].open_flag = 0; | ||
597 | phr->error = hr.error; | ||
598 | } else { | ||
599 | outstream_user_open[phm->adapter_index][phm-> | ||
600 | obj_index].open_flag = 1; | ||
601 | outstream_user_open[phm->adapter_index][phm-> | ||
602 | obj_index].h_owner = h_owner; | ||
603 | memcpy(phr, | ||
604 | &rESP_HPI_OSTREAM_OPEN[phm->adapter_index] | ||
605 | [phm->obj_index], | ||
606 | sizeof(rESP_HPI_OSTREAM_OPEN[0][0])); | ||
607 | } | ||
608 | } | ||
609 | hpios_msgxlock_un_lock(&msgx_lock); | ||
610 | } | ||
611 | |||
612 | static void outstream_close(struct hpi_message *phm, struct hpi_response *phr, | ||
613 | void *h_owner) | ||
614 | { | ||
615 | |||
616 | struct hpi_message hm; | ||
617 | struct hpi_response hr; | ||
618 | |||
619 | hpi_init_response(phr, HPI_OBJ_OSTREAM, HPI_OSTREAM_CLOSE, 0); | ||
620 | |||
621 | hpios_msgxlock_lock(&msgx_lock); | ||
622 | |||
623 | if (h_owner == | ||
624 | outstream_user_open[phm->adapter_index][phm-> | ||
625 | obj_index].h_owner) { | ||
626 | /* HPI_DEBUG_LOG(INFO,"closing adapter %d " | ||
627 | "outstream %d owned by %p\n", | ||
628 | phm->wAdapterIndex, phm->wObjIndex, hOwner); */ | ||
629 | outstream_user_open[phm->adapter_index][phm-> | ||
630 | obj_index].h_owner = NULL; | ||
631 | hpios_msgxlock_un_lock(&msgx_lock); | ||
632 | /* issue a reset */ | ||
633 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
634 | HPI_OSTREAM_RESET); | ||
635 | hm.adapter_index = phm->adapter_index; | ||
636 | hm.obj_index = phm->obj_index; | ||
637 | hw_entry_point(&hm, &hr); | ||
638 | hpios_msgxlock_lock(&msgx_lock); | ||
639 | if (hr.error) { | ||
640 | outstream_user_open[phm->adapter_index][phm-> | ||
641 | obj_index].h_owner = h_owner; | ||
642 | phr->error = hr.error; | ||
643 | } else { | ||
644 | outstream_user_open[phm->adapter_index][phm-> | ||
645 | obj_index].open_flag = 0; | ||
646 | outstream_user_open[phm->adapter_index][phm-> | ||
647 | obj_index].h_owner = NULL; | ||
648 | } | ||
649 | } else { | ||
650 | HPI_DEBUG_LOG(WARNING, | ||
651 | "%p trying to close %d outstream %d owned by %p\n", | ||
652 | h_owner, phm->adapter_index, phm->obj_index, | ||
653 | outstream_user_open[phm->adapter_index][phm-> | ||
654 | obj_index].h_owner); | ||
655 | phr->error = HPI_ERROR_OBJ_NOT_OPEN; | ||
656 | } | ||
657 | hpios_msgxlock_un_lock(&msgx_lock); | ||
658 | } | ||
659 | |||
660 | static u16 adapter_prepare(u16 adapter) | ||
661 | { | ||
662 | struct hpi_message hm; | ||
663 | struct hpi_response hr; | ||
664 | |||
665 | /* Open the adapter and streams */ | ||
666 | u16 i; | ||
667 | |||
668 | /* call to HPI_ADAPTER_OPEN */ | ||
669 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
670 | HPI_ADAPTER_OPEN); | ||
671 | hm.adapter_index = adapter; | ||
672 | hw_entry_point(&hm, &hr); | ||
673 | memcpy(&rESP_HPI_ADAPTER_OPEN[adapter], &hr, | ||
674 | sizeof(rESP_HPI_ADAPTER_OPEN[0])); | ||
675 | if (hr.error) | ||
676 | return hr.error; | ||
677 | |||
678 | /* call to HPI_ADAPTER_GET_INFO */ | ||
679 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
680 | HPI_ADAPTER_GET_INFO); | ||
681 | hm.adapter_index = adapter; | ||
682 | hw_entry_point(&hm, &hr); | ||
683 | if (hr.error) | ||
684 | return hr.error; | ||
685 | |||
686 | aDAPTER_INFO[adapter].num_outstreams = hr.u.a.num_outstreams; | ||
687 | aDAPTER_INFO[adapter].num_instreams = hr.u.a.num_instreams; | ||
688 | aDAPTER_INFO[adapter].type = hr.u.a.adapter_type; | ||
689 | |||
690 | gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list[adapter] = | ||
691 | hr.u.a.adapter_type; | ||
692 | gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters++; | ||
693 | if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters > HPI_MAX_ADAPTERS) | ||
694 | gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters = | ||
695 | HPI_MAX_ADAPTERS; | ||
696 | |||
697 | /* call to HPI_OSTREAM_OPEN */ | ||
698 | for (i = 0; i < aDAPTER_INFO[adapter].num_outstreams; i++) { | ||
699 | hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM, | ||
700 | HPI_OSTREAM_OPEN); | ||
701 | hm.adapter_index = adapter; | ||
702 | hm.obj_index = i; | ||
703 | hw_entry_point(&hm, &hr); | ||
704 | memcpy(&rESP_HPI_OSTREAM_OPEN[adapter][i], &hr, | ||
705 | sizeof(rESP_HPI_OSTREAM_OPEN[0][0])); | ||
706 | outstream_user_open[adapter][i].open_flag = 0; | ||
707 | outstream_user_open[adapter][i].h_owner = NULL; | ||
708 | } | ||
709 | |||
710 | /* call to HPI_ISTREAM_OPEN */ | ||
711 | for (i = 0; i < aDAPTER_INFO[adapter].num_instreams; i++) { | ||
712 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM, | ||
713 | HPI_ISTREAM_OPEN); | ||
714 | hm.adapter_index = adapter; | ||
715 | hm.obj_index = i; | ||
716 | hw_entry_point(&hm, &hr); | ||
717 | memcpy(&rESP_HPI_ISTREAM_OPEN[adapter][i], &hr, | ||
718 | sizeof(rESP_HPI_ISTREAM_OPEN[0][0])); | ||
719 | instream_user_open[adapter][i].open_flag = 0; | ||
720 | instream_user_open[adapter][i].h_owner = NULL; | ||
721 | } | ||
722 | |||
723 | /* call to HPI_MIXER_OPEN */ | ||
724 | hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_OPEN); | ||
725 | hm.adapter_index = adapter; | ||
726 | hw_entry_point(&hm, &hr); | ||
727 | memcpy(&rESP_HPI_MIXER_OPEN[adapter], &hr, | ||
728 | sizeof(rESP_HPI_MIXER_OPEN[0])); | ||
729 | |||
730 | return gRESP_HPI_SUBSYS_FIND_ADAPTERS.h.error; | ||
731 | } | ||
732 | |||
733 | static void HPIMSGX__reset(u16 adapter_index) | ||
734 | { | ||
735 | int i; | ||
736 | u16 adapter; | ||
737 | struct hpi_response hr; | ||
738 | |||
739 | if (adapter_index == HPIMSGX_ALLADAPTERS) { | ||
740 | /* reset all responses to contain errors */ | ||
741 | hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, | ||
742 | HPI_SUBSYS_FIND_ADAPTERS, 0); | ||
743 | memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr, | ||
744 | sizeof(&gRESP_HPI_SUBSYS_FIND_ADAPTERS)); | ||
745 | |||
746 | for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) { | ||
747 | |||
748 | hpi_init_response(&hr, HPI_OBJ_ADAPTER, | ||
749 | HPI_ADAPTER_OPEN, HPI_ERROR_BAD_ADAPTER); | ||
750 | memcpy(&rESP_HPI_ADAPTER_OPEN[adapter], &hr, | ||
751 | sizeof(rESP_HPI_ADAPTER_OPEN[adapter])); | ||
752 | |||
753 | hpi_init_response(&hr, HPI_OBJ_MIXER, HPI_MIXER_OPEN, | ||
754 | HPI_ERROR_INVALID_OBJ); | ||
755 | memcpy(&rESP_HPI_MIXER_OPEN[adapter], &hr, | ||
756 | sizeof(rESP_HPI_MIXER_OPEN[adapter])); | ||
757 | |||
758 | for (i = 0; i < HPI_MAX_STREAMS; i++) { | ||
759 | hpi_init_response(&hr, HPI_OBJ_OSTREAM, | ||
760 | HPI_OSTREAM_OPEN, | ||
761 | HPI_ERROR_INVALID_OBJ); | ||
762 | memcpy(&rESP_HPI_OSTREAM_OPEN[adapter][i], | ||
763 | &hr, | ||
764 | sizeof(rESP_HPI_OSTREAM_OPEN[adapter] | ||
765 | [i])); | ||
766 | hpi_init_response(&hr, HPI_OBJ_ISTREAM, | ||
767 | HPI_ISTREAM_OPEN, | ||
768 | HPI_ERROR_INVALID_OBJ); | ||
769 | memcpy(&rESP_HPI_ISTREAM_OPEN[adapter][i], | ||
770 | &hr, | ||
771 | sizeof(rESP_HPI_ISTREAM_OPEN[adapter] | ||
772 | [i])); | ||
773 | } | ||
774 | } | ||
775 | } else if (adapter_index < HPI_MAX_ADAPTERS) { | ||
776 | rESP_HPI_ADAPTER_OPEN[adapter_index].h.error = | ||
777 | HPI_ERROR_BAD_ADAPTER; | ||
778 | rESP_HPI_MIXER_OPEN[adapter_index].h.error = | ||
779 | HPI_ERROR_INVALID_OBJ; | ||
780 | for (i = 0; i < HPI_MAX_STREAMS; i++) { | ||
781 | rESP_HPI_OSTREAM_OPEN[adapter_index][i].h.error = | ||
782 | HPI_ERROR_INVALID_OBJ; | ||
783 | rESP_HPI_ISTREAM_OPEN[adapter_index][i].h.error = | ||
784 | HPI_ERROR_INVALID_OBJ; | ||
785 | } | ||
786 | if (gRESP_HPI_SUBSYS_FIND_ADAPTERS. | ||
787 | s.aw_adapter_list[adapter_index]) { | ||
788 | gRESP_HPI_SUBSYS_FIND_ADAPTERS. | ||
789 | s.aw_adapter_list[adapter_index] = 0; | ||
790 | gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters--; | ||
791 | } | ||
792 | } | ||
793 | } | ||
794 | |||
795 | static u16 HPIMSGX__init(struct hpi_message *phm, | ||
796 | /* HPI_SUBSYS_CREATE_ADAPTER structure with */ | ||
797 | /* resource list or NULL=find all */ | ||
798 | struct hpi_response *phr | ||
799 | /* response from HPI_ADAPTER_GET_INFO */ | ||
800 | ) | ||
801 | { | ||
802 | hpi_handler_func *entry_point_func; | ||
803 | struct hpi_response hr; | ||
804 | |||
805 | if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters >= HPI_MAX_ADAPTERS) | ||
806 | return HPI_ERROR_BAD_ADAPTER_NUMBER; | ||
807 | |||
808 | /* Init response here so we can pass in previous adapter list */ | ||
809 | hpi_init_response(&hr, phm->object, phm->function, | ||
810 | HPI_ERROR_INVALID_OBJ); | ||
811 | memcpy(hr.u.s.aw_adapter_list, | ||
812 | gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list, | ||
813 | sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list)); | ||
814 | |||
815 | entry_point_func = | ||
816 | hpi_lookup_entry_point_function(phm->u.s.resource.r.pci); | ||
817 | |||
818 | if (entry_point_func) { | ||
819 | HPI_DEBUG_MESSAGE(DEBUG, phm); | ||
820 | entry_point_func(phm, &hr); | ||
821 | } else { | ||
822 | phr->error = HPI_ERROR_PROCESSING_MESSAGE; | ||
823 | return phr->error; | ||
824 | } | ||
825 | if (hr.error == 0) { | ||
826 | /* the adapter was created succesfully | ||
827 | save the mapping for future use */ | ||
828 | hpi_entry_points[hr.u.s.adapter_index] = entry_point_func; | ||
829 | /* prepare adapter (pre-open streams etc.) */ | ||
830 | HPI_DEBUG_LOG(DEBUG, | ||
831 | "HPI_SUBSYS_CREATE_ADAPTER successful," | ||
832 | " preparing adapter\n"); | ||
833 | adapter_prepare(hr.u.s.adapter_index); | ||
834 | } | ||
835 | memcpy(phr, &hr, hr.size); | ||
836 | return phr->error; | ||
837 | } | ||
838 | |||
839 | static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner) | ||
840 | { | ||
841 | int i, adapter, adapter_limit; | ||
842 | |||
843 | if (!h_owner) | ||
844 | return; | ||
845 | |||
846 | if (adapter_index == HPIMSGX_ALLADAPTERS) { | ||
847 | adapter = 0; | ||
848 | adapter_limit = HPI_MAX_ADAPTERS; | ||
849 | } else { | ||
850 | adapter = adapter_index; | ||
851 | adapter_limit = adapter + 1; | ||
852 | } | ||
853 | |||
854 | for (; adapter < adapter_limit; adapter++) { | ||
855 | /* printk(KERN_INFO "Cleanup adapter #%d\n",wAdapter); */ | ||
856 | for (i = 0; i < HPI_MAX_STREAMS; i++) { | ||
857 | if (h_owner == | ||
858 | outstream_user_open[adapter][i].h_owner) { | ||
859 | struct hpi_message hm; | ||
860 | struct hpi_response hr; | ||
861 | |||
862 | HPI_DEBUG_LOG(DEBUG, | ||
863 | "close adapter %d ostream %d\n", | ||
864 | adapter, i); | ||
865 | |||
866 | hpi_init_message_response(&hm, &hr, | ||
867 | HPI_OBJ_OSTREAM, HPI_OSTREAM_RESET); | ||
868 | hm.adapter_index = (u16)adapter; | ||
869 | hm.obj_index = (u16)i; | ||
870 | hw_entry_point(&hm, &hr); | ||
871 | |||
872 | hm.function = HPI_OSTREAM_HOSTBUFFER_FREE; | ||
873 | hw_entry_point(&hm, &hr); | ||
874 | |||
875 | hm.function = HPI_OSTREAM_GROUP_RESET; | ||
876 | hw_entry_point(&hm, &hr); | ||
877 | |||
878 | outstream_user_open[adapter][i].open_flag = 0; | ||
879 | outstream_user_open[adapter][i].h_owner = | ||
880 | NULL; | ||
881 | } | ||
882 | if (h_owner == instream_user_open[adapter][i].h_owner) { | ||
883 | struct hpi_message hm; | ||
884 | struct hpi_response hr; | ||
885 | |||
886 | HPI_DEBUG_LOG(DEBUG, | ||
887 | "close adapter %d istream %d\n", | ||
888 | adapter, i); | ||
889 | |||
890 | hpi_init_message_response(&hm, &hr, | ||
891 | HPI_OBJ_ISTREAM, HPI_ISTREAM_RESET); | ||
892 | hm.adapter_index = (u16)adapter; | ||
893 | hm.obj_index = (u16)i; | ||
894 | hw_entry_point(&hm, &hr); | ||
895 | |||
896 | hm.function = HPI_ISTREAM_HOSTBUFFER_FREE; | ||
897 | hw_entry_point(&hm, &hr); | ||
898 | |||
899 | hm.function = HPI_ISTREAM_GROUP_RESET; | ||
900 | hw_entry_point(&hm, &hr); | ||
901 | |||
902 | instream_user_open[adapter][i].open_flag = 0; | ||
903 | instream_user_open[adapter][i].h_owner = NULL; | ||
904 | } | ||
905 | } | ||
906 | } | ||
907 | } | ||
diff --git a/sound/pci/asihpi/hpimsgx.h b/sound/pci/asihpi/hpimsgx.h new file mode 100644 index 00000000000..fd49e7542a8 --- /dev/null +++ b/sound/pci/asihpi/hpimsgx.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | HPI Extended Message Handler Functions | ||
20 | |||
21 | (C) Copyright AudioScience Inc. 1997-2003 | ||
22 | ******************************************************************************/ | ||
23 | |||
24 | #ifndef _HPIMSGX_H_ | ||
25 | #define _HPIMSGX_H_ | ||
26 | |||
27 | #include "hpi_internal.h" | ||
28 | |||
29 | #define HPIMSGX_ALLADAPTERS (0xFFFF) | ||
30 | |||
31 | void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr, | ||
32 | void *h_owner); | ||
33 | |||
34 | #define HPI_MESSAGE_LOWER_LAYER hpi_send_recv_ex | ||
35 | |||
36 | #endif /* _HPIMSGX_H_ */ | ||
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c new file mode 100644 index 00000000000..7396ac54e99 --- /dev/null +++ b/sound/pci/asihpi/hpioctl.c | |||
@@ -0,0 +1,484 @@ | |||
1 | /******************************************************************************* | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Common Linux HPI ioctl and module probe/remove functions | ||
20 | *******************************************************************************/ | ||
21 | #define SOURCEFILE_NAME "hpioctl.c" | ||
22 | |||
23 | #include "hpi_internal.h" | ||
24 | #include "hpimsginit.h" | ||
25 | #include "hpidebug.h" | ||
26 | #include "hpimsgx.h" | ||
27 | #include "hpioctl.h" | ||
28 | |||
29 | #include <linux/fs.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/moduleparam.h> | ||
32 | #include <asm/uaccess.h> | ||
33 | #include <linux/stringify.h> | ||
34 | |||
35 | #ifdef MODULE_FIRMWARE | ||
36 | MODULE_FIRMWARE("asihpi/dsp5000.bin"); | ||
37 | MODULE_FIRMWARE("asihpi/dsp6200.bin"); | ||
38 | MODULE_FIRMWARE("asihpi/dsp6205.bin"); | ||
39 | MODULE_FIRMWARE("asihpi/dsp6400.bin"); | ||
40 | MODULE_FIRMWARE("asihpi/dsp6600.bin"); | ||
41 | MODULE_FIRMWARE("asihpi/dsp8700.bin"); | ||
42 | MODULE_FIRMWARE("asihpi/dsp8900.bin"); | ||
43 | #endif | ||
44 | |||
45 | static int prealloc_stream_buf; | ||
46 | module_param(prealloc_stream_buf, int, S_IRUGO); | ||
47 | MODULE_PARM_DESC(prealloc_stream_buf, | ||
48 | "preallocate size for per-adapter stream buffer"); | ||
49 | |||
50 | /* Allow the debug level to be changed after module load. | ||
51 | E.g. echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel | ||
52 | */ | ||
53 | module_param(hpi_debug_level, int, S_IRUGO | S_IWUSR); | ||
54 | MODULE_PARM_DESC(hpi_debug_level, "debug verbosity 0..5"); | ||
55 | |||
56 | /* List of adapters found */ | ||
57 | static struct hpi_adapter adapters[HPI_MAX_ADAPTERS]; | ||
58 | |||
59 | /* Wrapper function to HPI_Message to enable dumping of the | ||
60 | message and response types. | ||
61 | */ | ||
62 | static void hpi_send_recv_f(struct hpi_message *phm, struct hpi_response *phr, | ||
63 | struct file *file) | ||
64 | { | ||
65 | int adapter = phm->adapter_index; | ||
66 | |||
67 | if ((adapter >= HPI_MAX_ADAPTERS || adapter < 0) | ||
68 | && (phm->object != HPI_OBJ_SUBSYSTEM)) | ||
69 | phr->error = HPI_ERROR_INVALID_OBJ_INDEX; | ||
70 | else | ||
71 | hpi_send_recv_ex(phm, phr, file); | ||
72 | } | ||
73 | |||
74 | /* This is called from hpifunc.c functions, called by ALSA | ||
75 | * (or other kernel process) In this case there is no file descriptor | ||
76 | * available for the message cache code | ||
77 | */ | ||
78 | void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr) | ||
79 | { | ||
80 | hpi_send_recv_f(phm, phr, HOWNER_KERNEL); | ||
81 | } | ||
82 | |||
83 | EXPORT_SYMBOL(hpi_send_recv); | ||
84 | /* for radio-asihpi */ | ||
85 | |||
86 | int asihpi_hpi_release(struct file *file) | ||
87 | { | ||
88 | struct hpi_message hm; | ||
89 | struct hpi_response hr; | ||
90 | |||
91 | /* HPI_DEBUG_LOG(INFO,"hpi_release file %p, pid %d\n", file, current->pid); */ | ||
92 | /* close the subsystem just in case the application forgot to. */ | ||
93 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
94 | HPI_SUBSYS_CLOSE); | ||
95 | hpi_send_recv_ex(&hm, &hr, file); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
100 | { | ||
101 | struct hpi_ioctl_linux __user *phpi_ioctl_data; | ||
102 | void __user *puhm; | ||
103 | void __user *puhr; | ||
104 | union hpi_message_buffer_v1 *hm; | ||
105 | union hpi_response_buffer_v1 *hr; | ||
106 | u16 res_max_size; | ||
107 | u32 uncopied_bytes; | ||
108 | struct hpi_adapter *pa = NULL; | ||
109 | int err = 0; | ||
110 | |||
111 | if (cmd != HPI_IOCTL_LINUX) | ||
112 | return -EINVAL; | ||
113 | |||
114 | hm = kmalloc(sizeof(*hm), GFP_KERNEL); | ||
115 | hr = kmalloc(sizeof(*hr), GFP_KERNEL); | ||
116 | if (!hm || !hr) { | ||
117 | err = -ENOMEM; | ||
118 | goto out; | ||
119 | } | ||
120 | |||
121 | phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg; | ||
122 | |||
123 | /* Read the message and response pointers from user space. */ | ||
124 | get_user(puhm, &phpi_ioctl_data->phm); | ||
125 | get_user(puhr, &phpi_ioctl_data->phr); | ||
126 | |||
127 | /* Now read the message size and data from user space. */ | ||
128 | get_user(hm->h.size, (u16 __user *)puhm); | ||
129 | if (hm->h.size > sizeof(*hm)) | ||
130 | hm->h.size = sizeof(*hm); | ||
131 | |||
132 | /*printk(KERN_INFO "message size %d\n", hm->h.wSize); */ | ||
133 | |||
134 | uncopied_bytes = copy_from_user(hm, puhm, hm->h.size); | ||
135 | if (uncopied_bytes) { | ||
136 | HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes); | ||
137 | err = -EFAULT; | ||
138 | goto out; | ||
139 | } | ||
140 | |||
141 | get_user(res_max_size, (u16 __user *)puhr); | ||
142 | /* printk(KERN_INFO "user response size %d\n", res_max_size); */ | ||
143 | if (res_max_size < sizeof(struct hpi_response_header)) { | ||
144 | HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size); | ||
145 | err = -EFAULT; | ||
146 | goto out; | ||
147 | } | ||
148 | |||
149 | pa = &adapters[hm->h.adapter_index]; | ||
150 | hr->h.size = 0; | ||
151 | if (hm->h.object == HPI_OBJ_SUBSYSTEM) { | ||
152 | switch (hm->h.function) { | ||
153 | case HPI_SUBSYS_CREATE_ADAPTER: | ||
154 | case HPI_SUBSYS_DELETE_ADAPTER: | ||
155 | /* Application must not use these functions! */ | ||
156 | hr->h.size = sizeof(hr->h); | ||
157 | hr->h.error = HPI_ERROR_INVALID_OPERATION; | ||
158 | hr->h.function = hm->h.function; | ||
159 | uncopied_bytes = copy_to_user(puhr, hr, hr->h.size); | ||
160 | if (uncopied_bytes) | ||
161 | err = -EFAULT; | ||
162 | else | ||
163 | err = 0; | ||
164 | goto out; | ||
165 | |||
166 | default: | ||
167 | hpi_send_recv_f(&hm->m0, &hr->r0, file); | ||
168 | } | ||
169 | } else { | ||
170 | u16 __user *ptr = NULL; | ||
171 | u32 size = 0; | ||
172 | |||
173 | /* -1=no data 0=read from user mem, 1=write to user mem */ | ||
174 | int wrflag = -1; | ||
175 | u32 adapter = hm->h.adapter_index; | ||
176 | |||
177 | if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) { | ||
178 | hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER, | ||
179 | HPI_ADAPTER_OPEN, | ||
180 | HPI_ERROR_BAD_ADAPTER_NUMBER); | ||
181 | |||
182 | uncopied_bytes = | ||
183 | copy_to_user(puhr, hr, sizeof(hr->h)); | ||
184 | if (uncopied_bytes) | ||
185 | err = -EFAULT; | ||
186 | else | ||
187 | err = 0; | ||
188 | goto out; | ||
189 | } | ||
190 | |||
191 | if (mutex_lock_interruptible(&adapters[adapter].mutex)) { | ||
192 | err = -EINTR; | ||
193 | goto out; | ||
194 | } | ||
195 | |||
196 | /* Dig out any pointers embedded in the message. */ | ||
197 | switch (hm->h.function) { | ||
198 | case HPI_OSTREAM_WRITE: | ||
199 | case HPI_ISTREAM_READ:{ | ||
200 | /* Yes, sparse, this is correct. */ | ||
201 | ptr = (u16 __user *)hm->m0.u.d.u.data.pb_data; | ||
202 | size = hm->m0.u.d.u.data.data_size; | ||
203 | |||
204 | /* Allocate buffer according to application request. | ||
205 | ?Is it better to alloc/free for the duration | ||
206 | of the transaction? | ||
207 | */ | ||
208 | if (pa->buffer_size < size) { | ||
209 | HPI_DEBUG_LOG(DEBUG, | ||
210 | "realloc adapter %d stream " | ||
211 | "buffer from %zd to %d\n", | ||
212 | hm->h.adapter_index, | ||
213 | pa->buffer_size, size); | ||
214 | if (pa->p_buffer) { | ||
215 | pa->buffer_size = 0; | ||
216 | vfree(pa->p_buffer); | ||
217 | } | ||
218 | pa->p_buffer = vmalloc(size); | ||
219 | if (pa->p_buffer) | ||
220 | pa->buffer_size = size; | ||
221 | else { | ||
222 | HPI_DEBUG_LOG(ERROR, | ||
223 | "HPI could not allocate " | ||
224 | "stream buffer size %d\n", | ||
225 | size); | ||
226 | |||
227 | mutex_unlock(&adapters | ||
228 | [adapter].mutex); | ||
229 | err = -EINVAL; | ||
230 | goto out; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | hm->m0.u.d.u.data.pb_data = pa->p_buffer; | ||
235 | if (hm->h.function == HPI_ISTREAM_READ) | ||
236 | /* from card, WRITE to user mem */ | ||
237 | wrflag = 1; | ||
238 | else | ||
239 | wrflag = 0; | ||
240 | break; | ||
241 | } | ||
242 | |||
243 | default: | ||
244 | size = 0; | ||
245 | break; | ||
246 | } | ||
247 | |||
248 | if (size && (wrflag == 0)) { | ||
249 | uncopied_bytes = | ||
250 | copy_from_user(pa->p_buffer, ptr, size); | ||
251 | if (uncopied_bytes) | ||
252 | HPI_DEBUG_LOG(WARNING, | ||
253 | "missed %d of %d " | ||
254 | "bytes from user\n", uncopied_bytes, | ||
255 | size); | ||
256 | } | ||
257 | |||
258 | hpi_send_recv_f(&hm->m0, &hr->r0, file); | ||
259 | |||
260 | if (size && (wrflag == 1)) { | ||
261 | uncopied_bytes = | ||
262 | copy_to_user(ptr, pa->p_buffer, size); | ||
263 | if (uncopied_bytes) | ||
264 | HPI_DEBUG_LOG(WARNING, | ||
265 | "missed %d of %d " "bytes to user\n", | ||
266 | uncopied_bytes, size); | ||
267 | } | ||
268 | |||
269 | mutex_unlock(&adapters[adapter].mutex); | ||
270 | } | ||
271 | |||
272 | /* on return response size must be set */ | ||
273 | /*printk(KERN_INFO "response size %d\n", hr->h.wSize); */ | ||
274 | |||
275 | if (!hr->h.size) { | ||
276 | HPI_DEBUG_LOG(ERROR, "response zero size\n"); | ||
277 | err = -EFAULT; | ||
278 | goto out; | ||
279 | } | ||
280 | |||
281 | if (hr->h.size > res_max_size) { | ||
282 | HPI_DEBUG_LOG(ERROR, "response too big %d %d\n", hr->h.size, | ||
283 | res_max_size); | ||
284 | /*HPI_DEBUG_MESSAGE(ERROR, hm); */ | ||
285 | err = -EFAULT; | ||
286 | goto out; | ||
287 | } | ||
288 | |||
289 | uncopied_bytes = copy_to_user(puhr, hr, hr->h.size); | ||
290 | if (uncopied_bytes) { | ||
291 | HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes); | ||
292 | err = -EFAULT; | ||
293 | goto out; | ||
294 | } | ||
295 | |||
296 | out: | ||
297 | kfree(hm); | ||
298 | kfree(hr); | ||
299 | return err; | ||
300 | } | ||
301 | |||
302 | int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, | ||
303 | const struct pci_device_id *pci_id) | ||
304 | { | ||
305 | int err, idx, nm; | ||
306 | unsigned int memlen; | ||
307 | struct hpi_message hm; | ||
308 | struct hpi_response hr; | ||
309 | struct hpi_adapter adapter; | ||
310 | struct hpi_pci pci; | ||
311 | |||
312 | memset(&adapter, 0, sizeof(adapter)); | ||
313 | |||
314 | printk(KERN_DEBUG "probe PCI device (%04x:%04x,%04x:%04x,%04x)\n", | ||
315 | pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor, | ||
316 | pci_dev->subsystem_device, pci_dev->devfn); | ||
317 | |||
318 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
319 | HPI_SUBSYS_CREATE_ADAPTER); | ||
320 | hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER, | ||
321 | HPI_ERROR_PROCESSING_MESSAGE); | ||
322 | |||
323 | hm.adapter_index = -1; /* an invalid index */ | ||
324 | |||
325 | /* fill in HPI_PCI information from kernel provided information */ | ||
326 | adapter.pci = pci_dev; | ||
327 | |||
328 | nm = HPI_MAX_ADAPTER_MEM_SPACES; | ||
329 | |||
330 | for (idx = 0; idx < nm; idx++) { | ||
331 | HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n", | ||
332 | idx, pci_dev->resource[idx].name, | ||
333 | (unsigned long long)pci_resource_start(pci_dev, idx), | ||
334 | (unsigned long long)pci_resource_end(pci_dev, idx), | ||
335 | (unsigned long long)pci_resource_flags(pci_dev, idx)); | ||
336 | |||
337 | if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) { | ||
338 | memlen = pci_resource_len(pci_dev, idx); | ||
339 | adapter.ap_remapped_mem_base[idx] = | ||
340 | ioremap(pci_resource_start(pci_dev, idx), | ||
341 | memlen); | ||
342 | if (!adapter.ap_remapped_mem_base[idx]) { | ||
343 | HPI_DEBUG_LOG(ERROR, | ||
344 | "ioremap failed, aborting\n"); | ||
345 | /* unmap previously mapped pci mem space */ | ||
346 | goto err; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | pci.ap_mem_base[idx] = adapter.ap_remapped_mem_base[idx]; | ||
351 | } | ||
352 | |||
353 | /* could replace Pci with direct pointer to pci_dev for linux | ||
354 | Instead wrap accessor functions for IDs etc. | ||
355 | Would it work for windows? | ||
356 | */ | ||
357 | pci.bus_number = pci_dev->bus->number; | ||
358 | pci.vendor_id = (u16)pci_dev->vendor; | ||
359 | pci.device_id = (u16)pci_dev->device; | ||
360 | pci.subsys_vendor_id = (u16)(pci_dev->subsystem_vendor & 0xffff); | ||
361 | pci.subsys_device_id = (u16)(pci_dev->subsystem_device & 0xffff); | ||
362 | pci.device_number = pci_dev->devfn; | ||
363 | pci.interrupt = pci_dev->irq; | ||
364 | pci.p_os_data = pci_dev; | ||
365 | |||
366 | hm.u.s.resource.bus_type = HPI_BUS_PCI; | ||
367 | hm.u.s.resource.r.pci = &pci; | ||
368 | |||
369 | /* call CreateAdapterObject on the relevant hpi module */ | ||
370 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
371 | if (hr.error) | ||
372 | goto err; | ||
373 | |||
374 | if (prealloc_stream_buf) { | ||
375 | adapter.p_buffer = vmalloc(prealloc_stream_buf); | ||
376 | if (!adapter.p_buffer) { | ||
377 | HPI_DEBUG_LOG(ERROR, | ||
378 | "HPI could not allocate " | ||
379 | "kernel buffer size %d\n", | ||
380 | prealloc_stream_buf); | ||
381 | goto err; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | adapter.index = hr.u.s.adapter_index; | ||
386 | adapter.type = hr.u.s.aw_adapter_list[adapter.index]; | ||
387 | hm.adapter_index = adapter.index; | ||
388 | |||
389 | err = hpi_adapter_open(NULL, adapter.index); | ||
390 | if (err) | ||
391 | goto err; | ||
392 | |||
393 | adapter.snd_card_asihpi = NULL; | ||
394 | /* WARNING can't init mutex in 'adapter' | ||
395 | * and then copy it to adapters[] ?!?! | ||
396 | */ | ||
397 | adapters[hr.u.s.adapter_index] = adapter; | ||
398 | mutex_init(&adapters[adapter.index].mutex); | ||
399 | pci_set_drvdata(pci_dev, &adapters[adapter.index]); | ||
400 | |||
401 | printk(KERN_INFO "probe found adapter ASI%04X HPI index #%d.\n", | ||
402 | adapter.type, adapter.index); | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | err: | ||
407 | for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) { | ||
408 | if (adapter.ap_remapped_mem_base[idx]) { | ||
409 | iounmap(adapter.ap_remapped_mem_base[idx]); | ||
410 | adapter.ap_remapped_mem_base[idx] = NULL; | ||
411 | } | ||
412 | } | ||
413 | |||
414 | if (adapter.p_buffer) { | ||
415 | adapter.buffer_size = 0; | ||
416 | vfree(adapter.p_buffer); | ||
417 | } | ||
418 | |||
419 | HPI_DEBUG_LOG(ERROR, "adapter_probe failed\n"); | ||
420 | return -ENODEV; | ||
421 | } | ||
422 | |||
423 | void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) | ||
424 | { | ||
425 | int idx; | ||
426 | struct hpi_message hm; | ||
427 | struct hpi_response hr; | ||
428 | struct hpi_adapter *pa; | ||
429 | pa = (struct hpi_adapter *)pci_get_drvdata(pci_dev); | ||
430 | |||
431 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
432 | HPI_SUBSYS_DELETE_ADAPTER); | ||
433 | hm.adapter_index = pa->index; | ||
434 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
435 | |||
436 | /* unmap PCI memory space, mapped during device init. */ | ||
437 | for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) { | ||
438 | if (pa->ap_remapped_mem_base[idx]) { | ||
439 | iounmap(pa->ap_remapped_mem_base[idx]); | ||
440 | pa->ap_remapped_mem_base[idx] = NULL; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | if (pa->p_buffer) { | ||
445 | pa->buffer_size = 0; | ||
446 | vfree(pa->p_buffer); | ||
447 | } | ||
448 | |||
449 | pci_set_drvdata(pci_dev, NULL); | ||
450 | /* | ||
451 | printk(KERN_INFO "PCI device (%04x:%04x,%04x:%04x,%04x)," | ||
452 | " HPI index # %d, removed.\n", | ||
453 | pci_dev->vendor, pci_dev->device, | ||
454 | pci_dev->subsystem_vendor, | ||
455 | pci_dev->subsystem_device, pci_dev->devfn, | ||
456 | pa->index); | ||
457 | */ | ||
458 | } | ||
459 | |||
460 | void __init asihpi_init(void) | ||
461 | { | ||
462 | struct hpi_message hm; | ||
463 | struct hpi_response hr; | ||
464 | |||
465 | memset(adapters, 0, sizeof(adapters)); | ||
466 | |||
467 | printk(KERN_INFO "ASIHPI driver %d.%02d.%02d\n", | ||
468 | HPI_VER_MAJOR(HPI_VER), HPI_VER_MINOR(HPI_VER), | ||
469 | HPI_VER_RELEASE(HPI_VER)); | ||
470 | |||
471 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
472 | HPI_SUBSYS_DRIVER_LOAD); | ||
473 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
474 | } | ||
475 | |||
476 | void asihpi_exit(void) | ||
477 | { | ||
478 | struct hpi_message hm; | ||
479 | struct hpi_response hr; | ||
480 | |||
481 | hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, | ||
482 | HPI_SUBSYS_DRIVER_UNLOAD); | ||
483 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
484 | } | ||
diff --git a/sound/pci/asihpi/hpioctl.h b/sound/pci/asihpi/hpioctl.h new file mode 100644 index 00000000000..847f72f03fe --- /dev/null +++ b/sound/pci/asihpi/hpioctl.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /******************************************************************************* | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Linux HPI ioctl, and shared module init functions | ||
20 | *******************************************************************************/ | ||
21 | |||
22 | int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, | ||
23 | const struct pci_device_id *pci_id); | ||
24 | void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev); | ||
25 | void __init asihpi_init(void); | ||
26 | void __exit asihpi_exit(void); | ||
27 | |||
28 | int asihpi_hpi_release(struct file *file); | ||
29 | |||
30 | long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | ||
31 | |||
32 | /* This is called from hpifunc.c functions, called by ALSA | ||
33 | * (or other kernel process) In this case there is no file descriptor | ||
34 | * available for the message cache code | ||
35 | */ | ||
36 | void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr); | ||
37 | |||
38 | #define HOWNER_KERNEL ((void *)-1) | ||
diff --git a/sound/pci/asihpi/hpios.c b/sound/pci/asihpi/hpios.c new file mode 100644 index 00000000000..de615cfdb95 --- /dev/null +++ b/sound/pci/asihpi/hpios.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | HPI Operating System function implementation for Linux | ||
20 | |||
21 | (C) Copyright AudioScience Inc. 1997-2003 | ||
22 | ******************************************************************************/ | ||
23 | #define SOURCEFILE_NAME "hpios.c" | ||
24 | #include "hpi_internal.h" | ||
25 | #include "hpidebug.h" | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/sched.h> | ||
28 | |||
29 | void hpios_delay_micro_seconds(u32 num_micro_sec) | ||
30 | { | ||
31 | if ((usecs_to_jiffies(num_micro_sec) > 1) && !in_interrupt()) { | ||
32 | /* MUST NOT SCHEDULE IN INTERRUPT CONTEXT! */ | ||
33 | schedule_timeout_uninterruptible(usecs_to_jiffies | ||
34 | (num_micro_sec)); | ||
35 | } else if (num_micro_sec <= 2000) | ||
36 | udelay(num_micro_sec); | ||
37 | else | ||
38 | mdelay(num_micro_sec / 1000); | ||
39 | |||
40 | } | ||
41 | |||
42 | void hpios_locked_mem_init(void) | ||
43 | { | ||
44 | } | ||
45 | |||
46 | /** Allocated an area of locked memory for bus master DMA operations. | ||
47 | |||
48 | On error, return -ENOMEM, and *pMemArea.size = 0 | ||
49 | */ | ||
50 | u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size, | ||
51 | struct pci_dev *pdev) | ||
52 | { | ||
53 | /*?? any benefit in using managed dmam_alloc_coherent? */ | ||
54 | p_mem_area->vaddr = | ||
55 | dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle, | ||
56 | GFP_DMA32 | GFP_KERNEL); | ||
57 | |||
58 | if (p_mem_area->vaddr) { | ||
59 | HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n", | ||
60 | size, (unsigned int)p_mem_area->dma_handle, | ||
61 | p_mem_area->vaddr); | ||
62 | p_mem_area->pdev = &pdev->dev; | ||
63 | p_mem_area->size = size; | ||
64 | return 0; | ||
65 | } else { | ||
66 | HPI_DEBUG_LOG(WARNING, | ||
67 | "failed to allocate %d bytes locked memory\n", size); | ||
68 | p_mem_area->size = 0; | ||
69 | return -ENOMEM; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area) | ||
74 | { | ||
75 | if (p_mem_area->size) { | ||
76 | dma_free_coherent(p_mem_area->pdev, p_mem_area->size, | ||
77 | p_mem_area->vaddr, p_mem_area->dma_handle); | ||
78 | HPI_DEBUG_LOG(DEBUG, "freed %lu bytes, dma 0x%x vma %p\n", | ||
79 | (unsigned long)p_mem_area->size, | ||
80 | (unsigned int)p_mem_area->dma_handle, | ||
81 | p_mem_area->vaddr); | ||
82 | p_mem_area->size = 0; | ||
83 | return 0; | ||
84 | } else { | ||
85 | return 1; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | void hpios_locked_mem_free_all(void) | ||
90 | { | ||
91 | } | ||
92 | |||
93 | void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx, | ||
94 | unsigned int length) | ||
95 | { | ||
96 | HPI_DEBUG_LOG(DEBUG, "mapping %d %s %08llx-%08llx %04llx len 0x%x\n", | ||
97 | idx, pci_dev->resource[idx].name, | ||
98 | (unsigned long long)pci_resource_start(pci_dev, idx), | ||
99 | (unsigned long long)pci_resource_end(pci_dev, idx), | ||
100 | (unsigned long long)pci_resource_flags(pci_dev, idx), length); | ||
101 | |||
102 | if (!(pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM)) { | ||
103 | HPI_DEBUG_LOG(ERROR, "not an io memory resource\n"); | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | if (length > pci_resource_len(pci_dev, idx)) { | ||
108 | HPI_DEBUG_LOG(ERROR, "resource too small for requested %d \n", | ||
109 | length); | ||
110 | return NULL; | ||
111 | } | ||
112 | |||
113 | return ioremap(pci_resource_start(pci_dev, idx), length); | ||
114 | } | ||
diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h new file mode 100644 index 00000000000..a62c3f1e5f0 --- /dev/null +++ b/sound/pci/asihpi/hpios.h | |||
@@ -0,0 +1,178 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | HPI Operating System Specific macros for Linux Kernel driver | ||
20 | |||
21 | (C) Copyright AudioScience Inc. 1997-2003 | ||
22 | ******************************************************************************/ | ||
23 | #ifndef _HPIOS_H_ | ||
24 | #define _HPIOS_H_ | ||
25 | |||
26 | #undef HPI_OS_LINUX_KERNEL | ||
27 | #define HPI_OS_LINUX_KERNEL | ||
28 | |||
29 | #define HPI_OS_DEFINED | ||
30 | #define HPI_KERNEL_MODE | ||
31 | |||
32 | #define HPI_REASSIGN_DUPLICATE_ADAPTER_IDX | ||
33 | |||
34 | #include <linux/io.h> | ||
35 | #include <asm/system.h> | ||
36 | #include <linux/ioctl.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/string.h> | ||
39 | #include <linux/device.h> | ||
40 | #include <linux/firmware.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/pci.h> | ||
43 | |||
44 | #define HPI_NO_OS_FILE_OPS | ||
45 | |||
46 | #ifdef CONFIG_64BIT | ||
47 | #define HPI64BIT | ||
48 | #endif | ||
49 | |||
50 | /** Details of a memory area allocated with pci_alloc_consistent | ||
51 | Need all info for parameters to pci_free_consistent | ||
52 | */ | ||
53 | struct consistent_dma_area { | ||
54 | struct device *pdev; | ||
55 | /* looks like dma-mapping dma_devres ?! */ | ||
56 | size_t size; | ||
57 | void *vaddr; | ||
58 | dma_addr_t dma_handle; | ||
59 | }; | ||
60 | |||
61 | static inline u16 hpios_locked_mem_get_phys_addr(struct consistent_dma_area | ||
62 | *locked_mem_handle, u32 *p_physical_addr) | ||
63 | { | ||
64 | *p_physical_addr = locked_mem_handle->dma_handle; | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static inline u16 hpios_locked_mem_get_virt_addr(struct consistent_dma_area | ||
69 | *locked_mem_handle, void **pp_virtual_addr) | ||
70 | { | ||
71 | *pp_virtual_addr = locked_mem_handle->vaddr; | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static inline u16 hpios_locked_mem_valid(struct consistent_dma_area | ||
76 | *locked_mem_handle) | ||
77 | { | ||
78 | return locked_mem_handle->size != 0; | ||
79 | } | ||
80 | |||
81 | struct hpi_ioctl_linux { | ||
82 | void __user *phm; | ||
83 | void __user *phr; | ||
84 | }; | ||
85 | |||
86 | /* Conflict?: H is already used by a number of drivers hid, bluetooth hci, | ||
87 | and some sound drivers sb16, hdsp, emu10k. AFAIK 0xFC is ununsed command | ||
88 | */ | ||
89 | #define HPI_IOCTL_LINUX _IOWR('H', 0xFC, struct hpi_ioctl_linux) | ||
90 | |||
91 | #define HPI_DEBUG_FLAG_ERROR KERN_ERR | ||
92 | #define HPI_DEBUG_FLAG_WARNING KERN_WARNING | ||
93 | #define HPI_DEBUG_FLAG_NOTICE KERN_NOTICE | ||
94 | #define HPI_DEBUG_FLAG_INFO KERN_INFO | ||
95 | #define HPI_DEBUG_FLAG_DEBUG KERN_DEBUG | ||
96 | #define HPI_DEBUG_FLAG_VERBOSE KERN_DEBUG /* kernel has no verbose */ | ||
97 | |||
98 | #include <linux/spinlock.h> | ||
99 | |||
100 | #define HPI_LOCKING | ||
101 | |||
102 | struct hpios_spinlock { | ||
103 | spinlock_t lock; /* SEE hpios_spinlock */ | ||
104 | int lock_context; | ||
105 | }; | ||
106 | |||
107 | /* The reason for all this evilness is that ALSA calls some of a drivers | ||
108 | * operators in atomic context, and some not. But all our functions channel | ||
109 | * through the HPI_Message conduit, so we can't handle the different context | ||
110 | * per function | ||
111 | */ | ||
112 | #define IN_LOCK_BH 1 | ||
113 | #define IN_LOCK_IRQ 0 | ||
114 | static inline void cond_lock(struct hpios_spinlock *l) | ||
115 | { | ||
116 | if (irqs_disabled()) { | ||
117 | /* NO bh or isr can execute on this processor, | ||
118 | so ordinary lock will do | ||
119 | */ | ||
120 | spin_lock(&((l)->lock)); | ||
121 | l->lock_context = IN_LOCK_IRQ; | ||
122 | } else { | ||
123 | spin_lock_bh(&((l)->lock)); | ||
124 | l->lock_context = IN_LOCK_BH; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | static inline void cond_unlock(struct hpios_spinlock *l) | ||
129 | { | ||
130 | if (l->lock_context == IN_LOCK_BH) | ||
131 | spin_unlock_bh(&((l)->lock)); | ||
132 | else | ||
133 | spin_unlock(&((l)->lock)); | ||
134 | } | ||
135 | |||
136 | #define hpios_msgxlock_init(obj) spin_lock_init(&(obj)->lock) | ||
137 | #define hpios_msgxlock_lock(obj) cond_lock(obj) | ||
138 | #define hpios_msgxlock_un_lock(obj) cond_unlock(obj) | ||
139 | |||
140 | #define hpios_dsplock_init(obj) spin_lock_init(&(obj)->dsp_lock.lock) | ||
141 | #define hpios_dsplock_lock(obj) cond_lock(&(obj)->dsp_lock) | ||
142 | #define hpios_dsplock_unlock(obj) cond_unlock(&(obj)->dsp_lock) | ||
143 | |||
144 | #ifdef CONFIG_SND_DEBUG | ||
145 | #define HPI_DEBUG | ||
146 | #endif | ||
147 | |||
148 | #define HPI_ALIST_LOCKING | ||
149 | #define hpios_alistlock_init(obj) spin_lock_init(&((obj)->list_lock.lock)) | ||
150 | #define hpios_alistlock_lock(obj) spin_lock(&((obj)->list_lock.lock)) | ||
151 | #define hpios_alistlock_un_lock(obj) spin_unlock(&((obj)->list_lock.lock)) | ||
152 | |||
153 | struct hpi_adapter { | ||
154 | /* mutex prevents contention for one card | ||
155 | between multiple user programs (via ioctl) */ | ||
156 | struct mutex mutex; | ||
157 | u16 index; | ||
158 | u16 type; | ||
159 | |||
160 | /* ALSA card structure */ | ||
161 | void *snd_card_asihpi; | ||
162 | |||
163 | char *p_buffer; | ||
164 | size_t buffer_size; | ||
165 | struct pci_dev *pci; | ||
166 | void __iomem *ap_remapped_mem_base[HPI_MAX_ADAPTER_MEM_SPACES]; | ||
167 | }; | ||
168 | |||
169 | static inline void hpios_unmap_io(void __iomem *addr, | ||
170 | unsigned long size) | ||
171 | { | ||
172 | iounmap(addr); | ||
173 | } | ||
174 | |||
175 | void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx, | ||
176 | unsigned int length); | ||
177 | |||
178 | #endif | ||
diff --git a/sound/pci/asihpi/hpipcida.h b/sound/pci/asihpi/hpipcida.h new file mode 100644 index 00000000000..bb30868ce1a --- /dev/null +++ b/sound/pci/asihpi/hpipcida.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | AudioScience HPI driver | ||
4 | Copyright (C) 1997-2010 AudioScience Inc. <support@audioscience.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of version 2 of the GNU General Public License as | ||
8 | published by the Free Software Foundation; | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Array initializer for PCI card IDs | ||
20 | |||
21 | (C) Copyright AudioScience Inc. 1998-2003 | ||
22 | *******************************************************************************/ | ||
23 | |||
24 | /*NOTE: when adding new lines to this header file | ||
25 | they MUST be grouped by HPI entry point. | ||
26 | */ | ||
27 | |||
28 | { | ||
29 | HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205, | ||
30 | HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0, | ||
31 | (kernel_ulong_t) HPI_6205} | ||
32 | , { | ||
33 | HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040, | ||
34 | HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0, | ||
35 | (kernel_ulong_t) HPI_6000} | ||
36 | , { | ||
37 | 0} | ||
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 9edc65059e3..6772070ed49 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
@@ -1139,40 +1139,28 @@ static void snd_cs4281_proc_read(struct snd_info_entry *entry, | |||
1139 | snd_iprintf(buffer, "Spurious end IRQs : %u\n", chip->spurious_dtc_irq); | 1139 | snd_iprintf(buffer, "Spurious end IRQs : %u\n", chip->spurious_dtc_irq); |
1140 | } | 1140 | } |
1141 | 1141 | ||
1142 | static long snd_cs4281_BA0_read(struct snd_info_entry *entry, | 1142 | static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry, |
1143 | void *file_private_data, | 1143 | void *file_private_data, |
1144 | struct file *file, char __user *buf, | 1144 | struct file *file, char __user *buf, |
1145 | unsigned long count, unsigned long pos) | 1145 | size_t count, loff_t pos) |
1146 | { | 1146 | { |
1147 | long size; | ||
1148 | struct cs4281 *chip = entry->private_data; | 1147 | struct cs4281 *chip = entry->private_data; |
1149 | 1148 | ||
1150 | size = count; | 1149 | if (copy_to_user_fromio(buf, chip->ba0 + pos, count)) |
1151 | if (pos + size > CS4281_BA0_SIZE) | 1150 | return -EFAULT; |
1152 | size = (long)CS4281_BA0_SIZE - pos; | 1151 | return count; |
1153 | if (size > 0) { | ||
1154 | if (copy_to_user_fromio(buf, chip->ba0 + pos, size)) | ||
1155 | return -EFAULT; | ||
1156 | } | ||
1157 | return size; | ||
1158 | } | 1152 | } |
1159 | 1153 | ||
1160 | static long snd_cs4281_BA1_read(struct snd_info_entry *entry, | 1154 | static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry, |
1161 | void *file_private_data, | 1155 | void *file_private_data, |
1162 | struct file *file, char __user *buf, | 1156 | struct file *file, char __user *buf, |
1163 | unsigned long count, unsigned long pos) | 1157 | size_t count, loff_t pos) |
1164 | { | 1158 | { |
1165 | long size; | ||
1166 | struct cs4281 *chip = entry->private_data; | 1159 | struct cs4281 *chip = entry->private_data; |
1167 | 1160 | ||
1168 | size = count; | 1161 | if (copy_to_user_fromio(buf, chip->ba1 + pos, count)) |
1169 | if (pos + size > CS4281_BA1_SIZE) | 1162 | return -EFAULT; |
1170 | size = (long)CS4281_BA1_SIZE - pos; | 1163 | return count; |
1171 | if (size > 0) { | ||
1172 | if (copy_to_user_fromio(buf, chip->ba1 + pos, size)) | ||
1173 | return -EFAULT; | ||
1174 | } | ||
1175 | return size; | ||
1176 | } | 1164 | } |
1177 | 1165 | ||
1178 | static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { | 1166 | static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { |
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 3f99a5e8528..aad37082cb6 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c | |||
@@ -2657,21 +2657,16 @@ static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { } | |||
2657 | * proc interface | 2657 | * proc interface |
2658 | */ | 2658 | */ |
2659 | 2659 | ||
2660 | static long snd_cs46xx_io_read(struct snd_info_entry *entry, void *file_private_data, | 2660 | static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry, |
2661 | struct file *file, char __user *buf, | 2661 | void *file_private_data, |
2662 | unsigned long count, unsigned long pos) | 2662 | struct file *file, char __user *buf, |
2663 | size_t count, loff_t pos) | ||
2663 | { | 2664 | { |
2664 | long size; | ||
2665 | struct snd_cs46xx_region *region = entry->private_data; | 2665 | struct snd_cs46xx_region *region = entry->private_data; |
2666 | 2666 | ||
2667 | size = count; | 2667 | if (copy_to_user_fromio(buf, region->remap_addr + pos, count)) |
2668 | if (pos + (size_t)size > region->size) | 2668 | return -EFAULT; |
2669 | size = region->size - pos; | 2669 | return count; |
2670 | if (size > 0) { | ||
2671 | if (copy_to_user_fromio(buf, region->remap_addr + pos, size)) | ||
2672 | return -EFAULT; | ||
2673 | } | ||
2674 | return size; | ||
2675 | } | 2670 | } |
2676 | 2671 | ||
2677 | static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { | 2672 | static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { |
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index baa7cd508cd..bc38dd4d071 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c | |||
@@ -341,15 +341,17 @@ static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry, | |||
341 | #define TOTAL_SIZE_CODE (0x200*8) | 341 | #define TOTAL_SIZE_CODE (0x200*8) |
342 | #define A_TOTAL_SIZE_CODE (0x400*8) | 342 | #define A_TOTAL_SIZE_CODE (0x400*8) |
343 | 343 | ||
344 | static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry, | 344 | static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry, |
345 | void *file_private_data, | 345 | void *file_private_data, |
346 | struct file *file, char __user *buf, | 346 | struct file *file, char __user *buf, |
347 | unsigned long count, unsigned long pos) | 347 | size_t count, loff_t pos) |
348 | { | 348 | { |
349 | long size; | ||
350 | struct snd_emu10k1 *emu = entry->private_data; | 349 | struct snd_emu10k1 *emu = entry->private_data; |
351 | unsigned int offset; | 350 | unsigned int offset; |
352 | int tram_addr = 0; | 351 | int tram_addr = 0; |
352 | unsigned int *tmp; | ||
353 | long res; | ||
354 | unsigned int idx; | ||
353 | 355 | ||
354 | if (!strcmp(entry->name, "fx8010_tram_addr")) { | 356 | if (!strcmp(entry->name, "fx8010_tram_addr")) { |
355 | offset = TANKMEMADDRREGBASE; | 357 | offset = TANKMEMADDRREGBASE; |
@@ -361,30 +363,25 @@ static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry, | |||
361 | } else { | 363 | } else { |
362 | offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; | 364 | offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; |
363 | } | 365 | } |
364 | size = count; | 366 | |
365 | if (pos + size > entry->size) | 367 | tmp = kmalloc(count + 8, GFP_KERNEL); |
366 | size = (long)entry->size - pos; | 368 | if (!tmp) |
367 | if (size > 0) { | 369 | return -ENOMEM; |
368 | unsigned int *tmp; | 370 | for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) { |
369 | long res; | 371 | unsigned int val; |
370 | unsigned int idx; | 372 | val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0); |
371 | if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL) | 373 | if (tram_addr && emu->audigy) { |
372 | return -ENOMEM; | 374 | val >>= 11; |
373 | for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++) | 375 | val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20; |
374 | if (tram_addr && emu->audigy) { | ||
375 | tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11; | ||
376 | tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20; | ||
377 | } else | ||
378 | tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0); | ||
379 | if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size)) | ||
380 | res = -EFAULT; | ||
381 | else { | ||
382 | res = size; | ||
383 | } | 376 | } |
384 | kfree(tmp); | 377 | tmp[idx] = val; |
385 | return res; | ||
386 | } | 378 | } |
387 | return 0; | 379 | if (copy_to_user(buf, ((char *)tmp) + (pos & 3), count)) |
380 | res = -EFAULT; | ||
381 | else | ||
382 | res = count; | ||
383 | kfree(tmp); | ||
384 | return res; | ||
388 | } | 385 | } |
389 | 386 | ||
390 | static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, | 387 | static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index ecaea9fb48e..23a58f0d6cb 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
@@ -104,6 +104,7 @@ | |||
104 | #include <linux/gameport.h> | 104 | #include <linux/gameport.h> |
105 | #include <linux/moduleparam.h> | 105 | #include <linux/moduleparam.h> |
106 | #include <linux/mutex.h> | 106 | #include <linux/mutex.h> |
107 | #include <linux/input.h> | ||
107 | 108 | ||
108 | #include <sound/core.h> | 109 | #include <sound/core.h> |
109 | #include <sound/pcm.h> | 110 | #include <sound/pcm.h> |
@@ -517,14 +518,9 @@ struct es1968 { | |||
517 | 518 | ||
518 | /* ALSA Stuff */ | 519 | /* ALSA Stuff */ |
519 | struct snd_ac97 *ac97; | 520 | struct snd_ac97 *ac97; |
520 | struct snd_kcontrol *master_switch; /* for h/w volume control */ | ||
521 | struct snd_kcontrol *master_volume; | ||
522 | |||
523 | struct snd_rawmidi *rmidi; | 521 | struct snd_rawmidi *rmidi; |
524 | 522 | ||
525 | spinlock_t reg_lock; | 523 | spinlock_t reg_lock; |
526 | spinlock_t ac97_lock; | ||
527 | struct tasklet_struct hwvol_tq; | ||
528 | unsigned int in_suspend; | 524 | unsigned int in_suspend; |
529 | 525 | ||
530 | /* Maestro Stuff */ | 526 | /* Maestro Stuff */ |
@@ -547,6 +543,16 @@ struct es1968 { | |||
547 | #ifdef SUPPORT_JOYSTICK | 543 | #ifdef SUPPORT_JOYSTICK |
548 | struct gameport *gameport; | 544 | struct gameport *gameport; |
549 | #endif | 545 | #endif |
546 | |||
547 | #ifdef CONFIG_SND_ES1968_INPUT | ||
548 | struct input_dev *input_dev; | ||
549 | char phys[64]; /* physical device path */ | ||
550 | #else | ||
551 | struct snd_kcontrol *master_switch; /* for h/w volume control */ | ||
552 | struct snd_kcontrol *master_volume; | ||
553 | spinlock_t ac97_lock; | ||
554 | struct tasklet_struct hwvol_tq; | ||
555 | #endif | ||
550 | }; | 556 | }; |
551 | 557 | ||
552 | static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); | 558 | static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); |
@@ -632,28 +638,38 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip) | |||
632 | static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) | 638 | static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) |
633 | { | 639 | { |
634 | struct es1968 *chip = ac97->private_data; | 640 | struct es1968 *chip = ac97->private_data; |
641 | #ifndef CONFIG_SND_ES1968_INPUT | ||
635 | unsigned long flags; | 642 | unsigned long flags; |
643 | #endif | ||
636 | 644 | ||
637 | snd_es1968_ac97_wait(chip); | 645 | snd_es1968_ac97_wait(chip); |
638 | 646 | ||
639 | /* Write the bus */ | 647 | /* Write the bus */ |
648 | #ifndef CONFIG_SND_ES1968_INPUT | ||
640 | spin_lock_irqsave(&chip->ac97_lock, flags); | 649 | spin_lock_irqsave(&chip->ac97_lock, flags); |
650 | #endif | ||
641 | outw(val, chip->io_port + ESM_AC97_DATA); | 651 | outw(val, chip->io_port + ESM_AC97_DATA); |
642 | /*msleep(1);*/ | 652 | /*msleep(1);*/ |
643 | outb(reg, chip->io_port + ESM_AC97_INDEX); | 653 | outb(reg, chip->io_port + ESM_AC97_INDEX); |
644 | /*msleep(1);*/ | 654 | /*msleep(1);*/ |
655 | #ifndef CONFIG_SND_ES1968_INPUT | ||
645 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 656 | spin_unlock_irqrestore(&chip->ac97_lock, flags); |
657 | #endif | ||
646 | } | 658 | } |
647 | 659 | ||
648 | static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | 660 | static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
649 | { | 661 | { |
650 | u16 data = 0; | 662 | u16 data = 0; |
651 | struct es1968 *chip = ac97->private_data; | 663 | struct es1968 *chip = ac97->private_data; |
664 | #ifndef CONFIG_SND_ES1968_INPUT | ||
652 | unsigned long flags; | 665 | unsigned long flags; |
666 | #endif | ||
653 | 667 | ||
654 | snd_es1968_ac97_wait(chip); | 668 | snd_es1968_ac97_wait(chip); |
655 | 669 | ||
670 | #ifndef CONFIG_SND_ES1968_INPUT | ||
656 | spin_lock_irqsave(&chip->ac97_lock, flags); | 671 | spin_lock_irqsave(&chip->ac97_lock, flags); |
672 | #endif | ||
657 | outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); | 673 | outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); |
658 | /*msleep(1);*/ | 674 | /*msleep(1);*/ |
659 | 675 | ||
@@ -661,7 +677,9 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short | |||
661 | data = inw(chip->io_port + ESM_AC97_DATA); | 677 | data = inw(chip->io_port + ESM_AC97_DATA); |
662 | /*msleep(1);*/ | 678 | /*msleep(1);*/ |
663 | } | 679 | } |
680 | #ifndef CONFIG_SND_ES1968_INPUT | ||
664 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 681 | spin_unlock_irqrestore(&chip->ac97_lock, flags); |
682 | #endif | ||
665 | 683 | ||
666 | return data; | 684 | return data; |
667 | } | 685 | } |
@@ -1874,13 +1892,17 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es) | |||
1874 | } | 1892 | } |
1875 | } | 1893 | } |
1876 | 1894 | ||
1877 | /* | 1895 | /* The hardware volume works by incrementing / decrementing 2 counters |
1878 | */ | 1896 | (without wrap around) in response to volume button presses and then |
1897 | generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 | ||
1898 | of a byte wide register. The meaning of bits 0 and 4 is unknown. */ | ||
1879 | static void es1968_update_hw_volume(unsigned long private_data) | 1899 | static void es1968_update_hw_volume(unsigned long private_data) |
1880 | { | 1900 | { |
1881 | struct es1968 *chip = (struct es1968 *) private_data; | 1901 | struct es1968 *chip = (struct es1968 *) private_data; |
1882 | int x, val; | 1902 | int x, val; |
1903 | #ifndef CONFIG_SND_ES1968_INPUT | ||
1883 | unsigned long flags; | 1904 | unsigned long flags; |
1905 | #endif | ||
1884 | 1906 | ||
1885 | /* Figure out which volume control button was pushed, | 1907 | /* Figure out which volume control button was pushed, |
1886 | based on differences from the default register | 1908 | based on differences from the default register |
@@ -1895,6 +1917,7 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1895 | if (chip->in_suspend) | 1917 | if (chip->in_suspend) |
1896 | return; | 1918 | return; |
1897 | 1919 | ||
1920 | #ifndef CONFIG_SND_ES1968_INPUT | ||
1898 | if (! chip->master_switch || ! chip->master_volume) | 1921 | if (! chip->master_switch || ! chip->master_volume) |
1899 | return; | 1922 | return; |
1900 | 1923 | ||
@@ -1937,6 +1960,35 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1937 | break; | 1960 | break; |
1938 | } | 1961 | } |
1939 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 1962 | spin_unlock_irqrestore(&chip->ac97_lock, flags); |
1963 | #else | ||
1964 | if (!chip->input_dev) | ||
1965 | return; | ||
1966 | |||
1967 | val = 0; | ||
1968 | switch (x) { | ||
1969 | case 0x88: | ||
1970 | /* The counters have not changed, yet we've received a HV | ||
1971 | interrupt. According to tests run by various people this | ||
1972 | happens when pressing the mute button. */ | ||
1973 | val = KEY_MUTE; | ||
1974 | break; | ||
1975 | case 0xaa: | ||
1976 | /* counters increased by 1 -> volume up */ | ||
1977 | val = KEY_VOLUMEUP; | ||
1978 | break; | ||
1979 | case 0x66: | ||
1980 | /* counters decreased by 1 -> volume down */ | ||
1981 | val = KEY_VOLUMEDOWN; | ||
1982 | break; | ||
1983 | } | ||
1984 | |||
1985 | if (val) { | ||
1986 | input_report_key(chip->input_dev, val, 1); | ||
1987 | input_sync(chip->input_dev); | ||
1988 | input_report_key(chip->input_dev, val, 0); | ||
1989 | input_sync(chip->input_dev); | ||
1990 | } | ||
1991 | #endif | ||
1940 | } | 1992 | } |
1941 | 1993 | ||
1942 | /* | 1994 | /* |
@@ -1953,7 +2005,11 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) | |||
1953 | outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); | 2005 | outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); |
1954 | 2006 | ||
1955 | if (event & ESM_HWVOL_IRQ) | 2007 | if (event & ESM_HWVOL_IRQ) |
2008 | #ifdef CONFIG_SND_ES1968_INPUT | ||
2009 | es1968_update_hw_volume((unsigned long)chip); | ||
2010 | #else | ||
1956 | tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */ | 2011 | tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */ |
2012 | #endif | ||
1957 | 2013 | ||
1958 | /* else ack 'em all, i imagine */ | 2014 | /* else ack 'em all, i imagine */ |
1959 | outb(0xFF, chip->io_port + 0x1A); | 2015 | outb(0xFF, chip->io_port + 0x1A); |
@@ -1993,7 +2049,9 @@ snd_es1968_mixer(struct es1968 *chip) | |||
1993 | { | 2049 | { |
1994 | struct snd_ac97_bus *pbus; | 2050 | struct snd_ac97_bus *pbus; |
1995 | struct snd_ac97_template ac97; | 2051 | struct snd_ac97_template ac97; |
2052 | #ifndef CONFIG_SND_ES1968_INPUT | ||
1996 | struct snd_ctl_elem_id elem_id; | 2053 | struct snd_ctl_elem_id elem_id; |
2054 | #endif | ||
1997 | int err; | 2055 | int err; |
1998 | static struct snd_ac97_bus_ops ops = { | 2056 | static struct snd_ac97_bus_ops ops = { |
1999 | .write = snd_es1968_ac97_write, | 2057 | .write = snd_es1968_ac97_write, |
@@ -2009,6 +2067,7 @@ snd_es1968_mixer(struct es1968 *chip) | |||
2009 | if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) | 2067 | if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) |
2010 | return err; | 2068 | return err; |
2011 | 2069 | ||
2070 | #ifndef CONFIG_SND_ES1968_INPUT | ||
2012 | /* attach master switch / volumes for h/w volume control */ | 2071 | /* attach master switch / volumes for h/w volume control */ |
2013 | memset(&elem_id, 0, sizeof(elem_id)); | 2072 | memset(&elem_id, 0, sizeof(elem_id)); |
2014 | elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 2073 | elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
@@ -2018,6 +2077,7 @@ snd_es1968_mixer(struct es1968 *chip) | |||
2018 | elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 2077 | elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
2019 | strcpy(elem_id.name, "Master Playback Volume"); | 2078 | strcpy(elem_id.name, "Master Playback Volume"); |
2020 | chip->master_volume = snd_ctl_find_id(chip->card, &elem_id); | 2079 | chip->master_volume = snd_ctl_find_id(chip->card, &elem_id); |
2080 | #endif | ||
2021 | 2081 | ||
2022 | return 0; | 2082 | return 0; |
2023 | } | 2083 | } |
@@ -2341,6 +2401,7 @@ static void snd_es1968_start_irq(struct es1968 *chip) | |||
2341 | w = ESM_HIRQ_DSIE | ESM_HIRQ_HW_VOLUME; | 2401 | w = ESM_HIRQ_DSIE | ESM_HIRQ_HW_VOLUME; |
2342 | if (chip->rmidi) | 2402 | if (chip->rmidi) |
2343 | w |= ESM_HIRQ_MPU401; | 2403 | w |= ESM_HIRQ_MPU401; |
2404 | outb(w, chip->io_port + 0x1A); | ||
2344 | outw(w, chip->io_port + ESM_PORT_HOST_IRQ); | 2405 | outw(w, chip->io_port + ESM_PORT_HOST_IRQ); |
2345 | } | 2406 | } |
2346 | 2407 | ||
@@ -2474,8 +2535,49 @@ static inline int snd_es1968_create_gameport(struct es1968 *chip, int dev) { ret | |||
2474 | static inline void snd_es1968_free_gameport(struct es1968 *chip) { } | 2535 | static inline void snd_es1968_free_gameport(struct es1968 *chip) { } |
2475 | #endif | 2536 | #endif |
2476 | 2537 | ||
2538 | #ifdef CONFIG_SND_ES1968_INPUT | ||
2539 | static int __devinit snd_es1968_input_register(struct es1968 *chip) | ||
2540 | { | ||
2541 | struct input_dev *input_dev; | ||
2542 | int err; | ||
2543 | |||
2544 | input_dev = input_allocate_device(); | ||
2545 | if (!input_dev) | ||
2546 | return -ENOMEM; | ||
2547 | |||
2548 | snprintf(chip->phys, sizeof(chip->phys), "pci-%s/input0", | ||
2549 | pci_name(chip->pci)); | ||
2550 | |||
2551 | input_dev->name = chip->card->driver; | ||
2552 | input_dev->phys = chip->phys; | ||
2553 | input_dev->id.bustype = BUS_PCI; | ||
2554 | input_dev->id.vendor = chip->pci->vendor; | ||
2555 | input_dev->id.product = chip->pci->device; | ||
2556 | input_dev->dev.parent = &chip->pci->dev; | ||
2557 | |||
2558 | __set_bit(EV_KEY, input_dev->evbit); | ||
2559 | __set_bit(KEY_MUTE, input_dev->keybit); | ||
2560 | __set_bit(KEY_VOLUMEDOWN, input_dev->keybit); | ||
2561 | __set_bit(KEY_VOLUMEUP, input_dev->keybit); | ||
2562 | |||
2563 | err = input_register_device(input_dev); | ||
2564 | if (err) { | ||
2565 | input_free_device(input_dev); | ||
2566 | return err; | ||
2567 | } | ||
2568 | |||
2569 | chip->input_dev = input_dev; | ||
2570 | return 0; | ||
2571 | } | ||
2572 | #endif /* CONFIG_SND_ES1968_INPUT */ | ||
2573 | |||
2477 | static int snd_es1968_free(struct es1968 *chip) | 2574 | static int snd_es1968_free(struct es1968 *chip) |
2478 | { | 2575 | { |
2576 | #ifdef CONFIG_SND_ES1968_INPUT | ||
2577 | if (chip->input_dev) | ||
2578 | input_unregister_device(chip->input_dev); | ||
2579 | #endif | ||
2580 | |||
2479 | if (chip->io_port) { | 2581 | if (chip->io_port) { |
2480 | if (chip->irq >= 0) | 2582 | if (chip->irq >= 0) |
2481 | synchronize_irq(chip->irq); | 2583 | synchronize_irq(chip->irq); |
@@ -2486,8 +2588,6 @@ static int snd_es1968_free(struct es1968 *chip) | |||
2486 | if (chip->irq >= 0) | 2588 | if (chip->irq >= 0) |
2487 | free_irq(chip->irq, chip); | 2589 | free_irq(chip->irq, chip); |
2488 | snd_es1968_free_gameport(chip); | 2590 | snd_es1968_free_gameport(chip); |
2489 | chip->master_switch = NULL; | ||
2490 | chip->master_volume = NULL; | ||
2491 | pci_release_regions(chip->pci); | 2591 | pci_release_regions(chip->pci); |
2492 | pci_disable_device(chip->pci); | 2592 | pci_disable_device(chip->pci); |
2493 | kfree(chip); | 2593 | kfree(chip); |
@@ -2558,9 +2658,11 @@ static int __devinit snd_es1968_create(struct snd_card *card, | |||
2558 | spin_lock_init(&chip->substream_lock); | 2658 | spin_lock_init(&chip->substream_lock); |
2559 | INIT_LIST_HEAD(&chip->buf_list); | 2659 | INIT_LIST_HEAD(&chip->buf_list); |
2560 | INIT_LIST_HEAD(&chip->substream_list); | 2660 | INIT_LIST_HEAD(&chip->substream_list); |
2561 | spin_lock_init(&chip->ac97_lock); | ||
2562 | mutex_init(&chip->memory_mutex); | 2661 | mutex_init(&chip->memory_mutex); |
2662 | #ifndef CONFIG_SND_ES1968_INPUT | ||
2663 | spin_lock_init(&chip->ac97_lock); | ||
2563 | tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip); | 2664 | tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip); |
2665 | #endif | ||
2564 | chip->card = card; | 2666 | chip->card = card; |
2565 | chip->pci = pci; | 2667 | chip->pci = pci; |
2566 | chip->irq = -1; | 2668 | chip->irq = -1; |
@@ -2713,6 +2815,13 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, | |||
2713 | 2815 | ||
2714 | snd_es1968_create_gameport(chip, dev); | 2816 | snd_es1968_create_gameport(chip, dev); |
2715 | 2817 | ||
2818 | #ifdef CONFIG_SND_ES1968_INPUT | ||
2819 | err = snd_es1968_input_register(chip); | ||
2820 | if (err) | ||
2821 | snd_printk(KERN_WARNING "Input device registration " | ||
2822 | "failed with error %i", err); | ||
2823 | #endif | ||
2824 | |||
2716 | snd_es1968_start_irq(chip); | 2825 | snd_es1968_start_irq(chip); |
2717 | 2826 | ||
2718 | chip->clock = clock[dev]; | 2827 | chip->clock = clock[dev]; |
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 567348b05b5..9194c3c1d04 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
@@ -145,6 +145,7 @@ config SND_HDA_CODEC_NVHDMI | |||
145 | 145 | ||
146 | config SND_HDA_CODEC_INTELHDMI | 146 | config SND_HDA_CODEC_INTELHDMI |
147 | bool "Build INTEL HDMI HD-audio codec support" | 147 | bool "Build INTEL HDMI HD-audio codec support" |
148 | select SND_DYNAMIC_MINORS | ||
148 | default y | 149 | default y |
149 | help | 150 | help |
150 | Say Y here to include INTEL HDMI HD-audio codec support in | 151 | Say Y here to include INTEL HDMI HD-audio codec support in |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0e76ac2b2ac..a3d638c8c1f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1209,8 +1209,7 @@ static void free_hda_cache(struct hda_cache_rec *cache) | |||
1209 | } | 1209 | } |
1210 | 1210 | ||
1211 | /* query the hash. allocate an entry if not found. */ | 1211 | /* query the hash. allocate an entry if not found. */ |
1212 | static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, | 1212 | static struct hda_cache_head *get_hash(struct hda_cache_rec *cache, u32 key) |
1213 | u32 key) | ||
1214 | { | 1213 | { |
1215 | u16 idx = key % (u16)ARRAY_SIZE(cache->hash); | 1214 | u16 idx = key % (u16)ARRAY_SIZE(cache->hash); |
1216 | u16 cur = cache->hash[idx]; | 1215 | u16 cur = cache->hash[idx]; |
@@ -1222,17 +1221,27 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, | |||
1222 | return info; | 1221 | return info; |
1223 | cur = info->next; | 1222 | cur = info->next; |
1224 | } | 1223 | } |
1224 | return NULL; | ||
1225 | } | ||
1225 | 1226 | ||
1226 | /* add a new hash entry */ | 1227 | /* query the hash. allocate an entry if not found. */ |
1227 | info = snd_array_new(&cache->buf); | 1228 | static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, |
1228 | if (!info) | 1229 | u32 key) |
1229 | return NULL; | 1230 | { |
1230 | cur = snd_array_index(&cache->buf, info); | 1231 | struct hda_cache_head *info = get_hash(cache, key); |
1231 | info->key = key; | 1232 | if (!info) { |
1232 | info->val = 0; | 1233 | u16 idx, cur; |
1233 | info->next = cache->hash[idx]; | 1234 | /* add a new hash entry */ |
1234 | cache->hash[idx] = cur; | 1235 | info = snd_array_new(&cache->buf); |
1235 | 1236 | if (!info) | |
1237 | return NULL; | ||
1238 | cur = snd_array_index(&cache->buf, info); | ||
1239 | info->key = key; | ||
1240 | info->val = 0; | ||
1241 | idx = key % (u16)ARRAY_SIZE(cache->hash); | ||
1242 | info->next = cache->hash[idx]; | ||
1243 | cache->hash[idx] = cur; | ||
1244 | } | ||
1236 | return info; | 1245 | return info; |
1237 | } | 1246 | } |
1238 | 1247 | ||
@@ -1461,6 +1470,8 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | |||
1461 | info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); | 1470 | info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); |
1462 | if (!info) | 1471 | if (!info) |
1463 | return 0; | 1472 | return 0; |
1473 | if (snd_BUG_ON(mask & ~0xff)) | ||
1474 | mask &= 0xff; | ||
1464 | val &= mask; | 1475 | val &= mask; |
1465 | val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; | 1476 | val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; |
1466 | if (info->vol[ch] == val) | 1477 | if (info->vol[ch] == val) |
@@ -1486,6 +1497,9 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | |||
1486 | int direction, int idx, int mask, int val) | 1497 | int direction, int idx, int mask, int val) |
1487 | { | 1498 | { |
1488 | int ch, ret = 0; | 1499 | int ch, ret = 0; |
1500 | |||
1501 | if (snd_BUG_ON(mask & ~0xff)) | ||
1502 | mask &= 0xff; | ||
1489 | for (ch = 0; ch < 2; ch++) | 1503 | for (ch = 0; ch < 2; ch++) |
1490 | ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, | 1504 | ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, |
1491 | idx, mask, val); | 1505 | idx, mask, val); |
@@ -2717,6 +2731,41 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | |||
2717 | EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); | 2731 | EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); |
2718 | 2732 | ||
2719 | /** | 2733 | /** |
2734 | * snd_hda_codec_update_cache - check cache and write the cmd only when needed | ||
2735 | * @codec: the HDA codec | ||
2736 | * @nid: NID to send the command | ||
2737 | * @direct: direct flag | ||
2738 | * @verb: the verb to send | ||
2739 | * @parm: the parameter for the verb | ||
2740 | * | ||
2741 | * This function works like snd_hda_codec_write_cache(), but it doesn't send | ||
2742 | * command if the parameter is already identical with the cached value. | ||
2743 | * If not, it sends the command and refreshes the cache. | ||
2744 | * | ||
2745 | * Returns 0 if successful, or a negative error code. | ||
2746 | */ | ||
2747 | int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, | ||
2748 | int direct, unsigned int verb, unsigned int parm) | ||
2749 | { | ||
2750 | struct hda_cache_head *c; | ||
2751 | u32 key; | ||
2752 | |||
2753 | /* parm may contain the verb stuff for get/set amp */ | ||
2754 | verb = verb | (parm >> 8); | ||
2755 | parm &= 0xff; | ||
2756 | key = build_cmd_cache_key(nid, verb); | ||
2757 | mutex_lock(&codec->bus->cmd_mutex); | ||
2758 | c = get_hash(&codec->cmd_cache, key); | ||
2759 | if (c && c->val == parm) { | ||
2760 | mutex_unlock(&codec->bus->cmd_mutex); | ||
2761 | return 0; | ||
2762 | } | ||
2763 | mutex_unlock(&codec->bus->cmd_mutex); | ||
2764 | return snd_hda_codec_write_cache(codec, nid, direct, verb, parm); | ||
2765 | } | ||
2766 | EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache); | ||
2767 | |||
2768 | /** | ||
2720 | * snd_hda_codec_resume_cache - Resume the all commands from the cache | 2769 | * snd_hda_codec_resume_cache - Resume the all commands from the cache |
2721 | * @codec: HD-audio codec | 2770 | * @codec: HD-audio codec |
2722 | * | 2771 | * |
@@ -4218,7 +4267,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
4218 | break; | 4267 | break; |
4219 | case AC_JACK_MIC_IN: { | 4268 | case AC_JACK_MIC_IN: { |
4220 | int preferred, alt; | 4269 | int preferred, alt; |
4221 | if (loc == AC_JACK_LOC_FRONT) { | 4270 | if (loc == AC_JACK_LOC_FRONT || |
4271 | (loc & 0x30) == AC_JACK_LOC_INTERNAL) { | ||
4222 | preferred = AUTO_PIN_FRONT_MIC; | 4272 | preferred = AUTO_PIN_FRONT_MIC; |
4223 | alt = AUTO_PIN_MIC; | 4273 | alt = AUTO_PIN_MIC; |
4224 | } else { | 4274 | } else { |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index b75da47571e..49e939e7e5c 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -885,9 +885,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | |||
885 | int direct, unsigned int verb, unsigned int parm); | 885 | int direct, unsigned int verb, unsigned int parm); |
886 | void snd_hda_sequence_write_cache(struct hda_codec *codec, | 886 | void snd_hda_sequence_write_cache(struct hda_codec *codec, |
887 | const struct hda_verb *seq); | 887 | const struct hda_verb *seq); |
888 | int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, | ||
889 | int direct, unsigned int verb, unsigned int parm); | ||
888 | void snd_hda_codec_resume_cache(struct hda_codec *codec); | 890 | void snd_hda_codec_resume_cache(struct hda_codec *codec); |
889 | #else | 891 | #else |
890 | #define snd_hda_codec_write_cache snd_hda_codec_write | 892 | #define snd_hda_codec_write_cache snd_hda_codec_write |
893 | #define snd_hda_codec_update_cache snd_hda_codec_write | ||
891 | #define snd_hda_sequence_write_cache snd_hda_sequence_write | 894 | #define snd_hda_sequence_write_cache snd_hda_sequence_write |
892 | #endif | 895 | #endif |
893 | 896 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cec68152dcb..170610e1d7d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -84,7 +84,7 @@ module_param_array(bdl_pos_adj, int, NULL, 0644); | |||
84 | MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); | 84 | MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); |
85 | module_param_array(probe_mask, int, NULL, 0444); | 85 | module_param_array(probe_mask, int, NULL, 0444); |
86 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); | 86 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); |
87 | module_param_array(probe_only, bool, NULL, 0444); | 87 | module_param_array(probe_only, int, NULL, 0444); |
88 | MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); | 88 | MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); |
89 | module_param(single_cmd, bool, 0444); | 89 | module_param(single_cmd, bool, 0444); |
90 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " | 90 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " |
@@ -174,7 +174,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); | |||
174 | #define ICH6_GSTS_FSTS (1 << 1) /* flush status */ | 174 | #define ICH6_GSTS_FSTS (1 << 1) /* flush status */ |
175 | #define ICH6_REG_INTCTL 0x20 | 175 | #define ICH6_REG_INTCTL 0x20 |
176 | #define ICH6_REG_INTSTS 0x24 | 176 | #define ICH6_REG_INTSTS 0x24 |
177 | #define ICH6_REG_WALCLK 0x30 | 177 | #define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ |
178 | #define ICH6_REG_SYNC 0x34 | 178 | #define ICH6_REG_SYNC 0x34 |
179 | #define ICH6_REG_CORBLBASE 0x40 | 179 | #define ICH6_REG_CORBLBASE 0x40 |
180 | #define ICH6_REG_CORBUBASE 0x44 | 180 | #define ICH6_REG_CORBUBASE 0x44 |
@@ -340,8 +340,8 @@ struct azx_dev { | |||
340 | unsigned int period_bytes; /* size of the period in bytes */ | 340 | unsigned int period_bytes; /* size of the period in bytes */ |
341 | unsigned int frags; /* number for period in the play buffer */ | 341 | unsigned int frags; /* number for period in the play buffer */ |
342 | unsigned int fifo_size; /* FIFO size */ | 342 | unsigned int fifo_size; /* FIFO size */ |
343 | unsigned long start_jiffies; /* start + minimum jiffies */ | 343 | unsigned long start_wallclk; /* start + minimum wallclk */ |
344 | unsigned long min_jiffies; /* minimum jiffies before position is valid */ | 344 | unsigned long period_wallclk; /* wallclk for period */ |
345 | 345 | ||
346 | void __iomem *sd_addr; /* stream descriptor pointer */ | 346 | void __iomem *sd_addr; /* stream descriptor pointer */ |
347 | 347 | ||
@@ -361,7 +361,6 @@ struct azx_dev { | |||
361 | unsigned int opened :1; | 361 | unsigned int opened :1; |
362 | unsigned int running :1; | 362 | unsigned int running :1; |
363 | unsigned int irq_pending :1; | 363 | unsigned int irq_pending :1; |
364 | unsigned int start_flag: 1; /* stream full start flag */ | ||
365 | /* | 364 | /* |
366 | * For VIA: | 365 | * For VIA: |
367 | * A flag to ensure DMA position is 0 | 366 | * A flag to ensure DMA position is 0 |
@@ -425,7 +424,7 @@ struct azx { | |||
425 | struct snd_dma_buffer posbuf; | 424 | struct snd_dma_buffer posbuf; |
426 | 425 | ||
427 | /* flags */ | 426 | /* flags */ |
428 | int position_fix; | 427 | int position_fix[2]; /* for both playback/capture streams */ |
429 | int poll_count; | 428 | int poll_count; |
430 | unsigned int running :1; | 429 | unsigned int running :1; |
431 | unsigned int initialized :1; | 430 | unsigned int initialized :1; |
@@ -858,10 +857,13 @@ static void azx_power_notify(struct hda_bus *bus); | |||
858 | #endif | 857 | #endif |
859 | 858 | ||
860 | /* reset codec link */ | 859 | /* reset codec link */ |
861 | static int azx_reset(struct azx *chip) | 860 | static int azx_reset(struct azx *chip, int full_reset) |
862 | { | 861 | { |
863 | int count; | 862 | int count; |
864 | 863 | ||
864 | if (!full_reset) | ||
865 | goto __skip; | ||
866 | |||
865 | /* clear STATESTS */ | 867 | /* clear STATESTS */ |
866 | azx_writeb(chip, STATESTS, STATESTS_INT_MASK); | 868 | azx_writeb(chip, STATESTS, STATESTS_INT_MASK); |
867 | 869 | ||
@@ -887,6 +889,7 @@ static int azx_reset(struct azx *chip) | |||
887 | /* Brent Chartrand said to wait >= 540us for codecs to initialize */ | 889 | /* Brent Chartrand said to wait >= 540us for codecs to initialize */ |
888 | msleep(1); | 890 | msleep(1); |
889 | 891 | ||
892 | __skip: | ||
890 | /* check to see if controller is ready */ | 893 | /* check to see if controller is ready */ |
891 | if (!azx_readb(chip, GCTL)) { | 894 | if (!azx_readb(chip, GCTL)) { |
892 | snd_printd(SFX "azx_reset: controller not ready!\n"); | 895 | snd_printd(SFX "azx_reset: controller not ready!\n"); |
@@ -998,13 +1001,13 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) | |||
998 | /* | 1001 | /* |
999 | * reset and start the controller registers | 1002 | * reset and start the controller registers |
1000 | */ | 1003 | */ |
1001 | static void azx_init_chip(struct azx *chip) | 1004 | static void azx_init_chip(struct azx *chip, int full_reset) |
1002 | { | 1005 | { |
1003 | if (chip->initialized) | 1006 | if (chip->initialized) |
1004 | return; | 1007 | return; |
1005 | 1008 | ||
1006 | /* reset controller */ | 1009 | /* reset controller */ |
1007 | azx_reset(chip); | 1010 | azx_reset(chip, full_reset); |
1008 | 1011 | ||
1009 | /* initialize interrupts */ | 1012 | /* initialize interrupts */ |
1010 | azx_int_clear(chip); | 1013 | azx_int_clear(chip); |
@@ -1302,8 +1305,10 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
1302 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr)); | 1305 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr)); |
1303 | 1306 | ||
1304 | /* enable the position buffer */ | 1307 | /* enable the position buffer */ |
1305 | if (chip->position_fix == POS_FIX_POSBUF || | 1308 | if (chip->position_fix[0] == POS_FIX_POSBUF || |
1306 | chip->position_fix == POS_FIX_AUTO || | 1309 | chip->position_fix[0] == POS_FIX_AUTO || |
1310 | chip->position_fix[1] == POS_FIX_POSBUF || | ||
1311 | chip->position_fix[1] == POS_FIX_AUTO || | ||
1307 | chip->via_dmapos_patch) { | 1312 | chip->via_dmapos_patch) { |
1308 | if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) | 1313 | if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) |
1309 | azx_writel(chip, DPLBASE, | 1314 | azx_writel(chip, DPLBASE, |
@@ -1348,7 +1353,7 @@ static void azx_bus_reset(struct hda_bus *bus) | |||
1348 | 1353 | ||
1349 | bus->in_reset = 1; | 1354 | bus->in_reset = 1; |
1350 | azx_stop_chip(chip); | 1355 | azx_stop_chip(chip); |
1351 | azx_init_chip(chip); | 1356 | azx_init_chip(chip, 1); |
1352 | #ifdef CONFIG_PM | 1357 | #ifdef CONFIG_PM |
1353 | if (chip->initialized) { | 1358 | if (chip->initialized) { |
1354 | int i; | 1359 | int i; |
@@ -1422,7 +1427,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) | |||
1422 | * get back to the sanity state. | 1427 | * get back to the sanity state. |
1423 | */ | 1428 | */ |
1424 | azx_stop_chip(chip); | 1429 | azx_stop_chip(chip); |
1425 | azx_init_chip(chip); | 1430 | azx_init_chip(chip, 1); |
1426 | } | 1431 | } |
1427 | } | 1432 | } |
1428 | } | 1433 | } |
@@ -1670,8 +1675,9 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | |||
1670 | return err; | 1675 | return err; |
1671 | } | 1676 | } |
1672 | 1677 | ||
1673 | azx_dev->min_jiffies = (runtime->period_size * HZ) / | 1678 | /* wallclk has 24Mhz clock source */ |
1674 | (runtime->rate * 2); | 1679 | azx_dev->period_wallclk = (((runtime->period_size * 24000) / |
1680 | runtime->rate) * 1000); | ||
1675 | azx_setup_controller(chip, azx_dev); | 1681 | azx_setup_controller(chip, azx_dev); |
1676 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 1682 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
1677 | azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; | 1683 | azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; |
@@ -1725,14 +1731,15 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1725 | if (s->pcm->card != substream->pcm->card) | 1731 | if (s->pcm->card != substream->pcm->card) |
1726 | continue; | 1732 | continue; |
1727 | azx_dev = get_azx_dev(s); | 1733 | azx_dev = get_azx_dev(s); |
1728 | if (rstart) { | 1734 | if (start) { |
1729 | azx_dev->start_flag = 1; | 1735 | azx_dev->start_wallclk = azx_readl(chip, WALLCLK); |
1730 | azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies; | 1736 | if (!rstart) |
1731 | } | 1737 | azx_dev->start_wallclk -= |
1732 | if (start) | 1738 | azx_dev->period_wallclk; |
1733 | azx_stream_start(chip, azx_dev); | 1739 | azx_stream_start(chip, azx_dev); |
1734 | else | 1740 | } else { |
1735 | azx_stream_stop(chip, azx_dev); | 1741 | azx_stream_stop(chip, azx_dev); |
1742 | } | ||
1736 | azx_dev->running = start; | 1743 | azx_dev->running = start; |
1737 | } | 1744 | } |
1738 | spin_unlock(&chip->reg_lock); | 1745 | spin_unlock(&chip->reg_lock); |
@@ -1843,13 +1850,16 @@ static unsigned int azx_get_position(struct azx *chip, | |||
1843 | 1850 | ||
1844 | if (chip->via_dmapos_patch) | 1851 | if (chip->via_dmapos_patch) |
1845 | pos = azx_via_get_position(chip, azx_dev); | 1852 | pos = azx_via_get_position(chip, azx_dev); |
1846 | else if (chip->position_fix == POS_FIX_POSBUF || | 1853 | else { |
1847 | chip->position_fix == POS_FIX_AUTO) { | 1854 | int stream = azx_dev->substream->stream; |
1848 | /* use the position buffer */ | 1855 | if (chip->position_fix[stream] == POS_FIX_POSBUF || |
1849 | pos = le32_to_cpu(*azx_dev->posbuf); | 1856 | chip->position_fix[stream] == POS_FIX_AUTO) { |
1850 | } else { | 1857 | /* use the position buffer */ |
1851 | /* read LPIB */ | 1858 | pos = le32_to_cpu(*azx_dev->posbuf); |
1852 | pos = azx_sd_readl(azx_dev, SD_LPIB); | 1859 | } else { |
1860 | /* read LPIB */ | ||
1861 | pos = azx_sd_readl(azx_dev, SD_LPIB); | ||
1862 | } | ||
1853 | } | 1863 | } |
1854 | if (pos >= azx_dev->bufsize) | 1864 | if (pos >= azx_dev->bufsize) |
1855 | pos = 0; | 1865 | pos = 0; |
@@ -1876,32 +1886,35 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | |||
1876 | */ | 1886 | */ |
1877 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | 1887 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) |
1878 | { | 1888 | { |
1889 | u32 wallclk; | ||
1879 | unsigned int pos; | 1890 | unsigned int pos; |
1891 | int stream; | ||
1880 | 1892 | ||
1881 | if (azx_dev->start_flag && | 1893 | wallclk = azx_readl(chip, WALLCLK) - azx_dev->start_wallclk; |
1882 | time_before_eq(jiffies, azx_dev->start_jiffies)) | 1894 | if (wallclk < (azx_dev->period_wallclk * 2) / 3) |
1883 | return -1; /* bogus (too early) interrupt */ | 1895 | return -1; /* bogus (too early) interrupt */ |
1884 | azx_dev->start_flag = 0; | ||
1885 | 1896 | ||
1897 | stream = azx_dev->substream->stream; | ||
1886 | pos = azx_get_position(chip, azx_dev); | 1898 | pos = azx_get_position(chip, azx_dev); |
1887 | if (chip->position_fix == POS_FIX_AUTO) { | 1899 | if (chip->position_fix[stream] == POS_FIX_AUTO) { |
1888 | if (!pos) { | 1900 | if (!pos) { |
1889 | printk(KERN_WARNING | 1901 | printk(KERN_WARNING |
1890 | "hda-intel: Invalid position buffer, " | 1902 | "hda-intel: Invalid position buffer, " |
1891 | "using LPIB read method instead.\n"); | 1903 | "using LPIB read method instead.\n"); |
1892 | chip->position_fix = POS_FIX_LPIB; | 1904 | chip->position_fix[stream] = POS_FIX_LPIB; |
1893 | pos = azx_get_position(chip, azx_dev); | 1905 | pos = azx_get_position(chip, azx_dev); |
1894 | } else | 1906 | } else |
1895 | chip->position_fix = POS_FIX_POSBUF; | 1907 | chip->position_fix[stream] = POS_FIX_POSBUF; |
1896 | } | 1908 | } |
1897 | 1909 | ||
1898 | if (!bdl_pos_adj[chip->dev_index]) | ||
1899 | return 1; /* no delayed ack */ | ||
1900 | if (WARN_ONCE(!azx_dev->period_bytes, | 1910 | if (WARN_ONCE(!azx_dev->period_bytes, |
1901 | "hda-intel: zero azx_dev->period_bytes")) | 1911 | "hda-intel: zero azx_dev->period_bytes")) |
1902 | return 0; /* this shouldn't happen! */ | 1912 | return -1; /* this shouldn't happen! */ |
1903 | if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) | 1913 | if (wallclk <= azx_dev->period_wallclk && |
1904 | return 0; /* NG - it's below the period boundary */ | 1914 | pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) |
1915 | /* NG - it's below the first next period boundary */ | ||
1916 | return bdl_pos_adj[chip->dev_index] ? 0 : -1; | ||
1917 | azx_dev->start_wallclk = wallclk; | ||
1905 | return 1; /* OK, it's fine */ | 1918 | return 1; /* OK, it's fine */ |
1906 | } | 1919 | } |
1907 | 1920 | ||
@@ -1911,7 +1924,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | |||
1911 | static void azx_irq_pending_work(struct work_struct *work) | 1924 | static void azx_irq_pending_work(struct work_struct *work) |
1912 | { | 1925 | { |
1913 | struct azx *chip = container_of(work, struct azx, irq_pending_work); | 1926 | struct azx *chip = container_of(work, struct azx, irq_pending_work); |
1914 | int i, pending; | 1927 | int i, pending, ok; |
1915 | 1928 | ||
1916 | if (!chip->irq_pending_warned) { | 1929 | if (!chip->irq_pending_warned) { |
1917 | printk(KERN_WARNING | 1930 | printk(KERN_WARNING |
@@ -1930,11 +1943,14 @@ static void azx_irq_pending_work(struct work_struct *work) | |||
1930 | !azx_dev->substream || | 1943 | !azx_dev->substream || |
1931 | !azx_dev->running) | 1944 | !azx_dev->running) |
1932 | continue; | 1945 | continue; |
1933 | if (azx_position_ok(chip, azx_dev)) { | 1946 | ok = azx_position_ok(chip, azx_dev); |
1947 | if (ok > 0) { | ||
1934 | azx_dev->irq_pending = 0; | 1948 | azx_dev->irq_pending = 0; |
1935 | spin_unlock(&chip->reg_lock); | 1949 | spin_unlock(&chip->reg_lock); |
1936 | snd_pcm_period_elapsed(azx_dev->substream); | 1950 | snd_pcm_period_elapsed(azx_dev->substream); |
1937 | spin_lock(&chip->reg_lock); | 1951 | spin_lock(&chip->reg_lock); |
1952 | } else if (ok < 0) { | ||
1953 | pending = 0; /* too early */ | ||
1938 | } else | 1954 | } else |
1939 | pending++; | 1955 | pending++; |
1940 | } | 1956 | } |
@@ -2112,7 +2128,7 @@ static void azx_power_notify(struct hda_bus *bus) | |||
2112 | } | 2128 | } |
2113 | } | 2129 | } |
2114 | if (power_on) | 2130 | if (power_on) |
2115 | azx_init_chip(chip); | 2131 | azx_init_chip(chip, 1); |
2116 | else if (chip->running && power_save_controller && | 2132 | else if (chip->running && power_save_controller && |
2117 | !bus->power_keep_link_on) | 2133 | !bus->power_keep_link_on) |
2118 | azx_stop_chip(chip); | 2134 | azx_stop_chip(chip); |
@@ -2182,7 +2198,7 @@ static int azx_resume(struct pci_dev *pci) | |||
2182 | azx_init_pci(chip); | 2198 | azx_init_pci(chip); |
2183 | 2199 | ||
2184 | if (snd_hda_codecs_inuse(chip->bus)) | 2200 | if (snd_hda_codecs_inuse(chip->bus)) |
2185 | azx_init_chip(chip); | 2201 | azx_init_chip(chip, 1); |
2186 | 2202 | ||
2187 | snd_hda_resume(chip->bus); | 2203 | snd_hda_resume(chip->bus); |
2188 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 2204 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
@@ -2431,7 +2447,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
2431 | chip->dev_index = dev; | 2447 | chip->dev_index = dev; |
2432 | INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); | 2448 | INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); |
2433 | 2449 | ||
2434 | chip->position_fix = check_position_fix(chip, position_fix[dev]); | 2450 | chip->position_fix[0] = chip->position_fix[1] = |
2451 | check_position_fix(chip, position_fix[dev]); | ||
2435 | check_probe_mask(chip, dev); | 2452 | check_probe_mask(chip, dev); |
2436 | 2453 | ||
2437 | chip->single_cmd = single_cmd; | 2454 | chip->single_cmd = single_cmd; |
@@ -2577,7 +2594,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
2577 | 2594 | ||
2578 | /* initialize chip */ | 2595 | /* initialize chip */ |
2579 | azx_init_pci(chip); | 2596 | azx_init_pci(chip); |
2580 | azx_init_chip(chip); | 2597 | azx_init_chip(chip, (probe_only[dev] & 2) == 0); |
2581 | 2598 | ||
2582 | /* codec detection */ | 2599 | /* codec detection */ |
2583 | if (!chip->codec_mask) { | 2600 | if (!chip->codec_mask) { |
@@ -2666,7 +2683,7 @@ static int __devinit azx_probe(struct pci_dev *pci, | |||
2666 | goto out_free; | 2683 | goto out_free; |
2667 | } | 2684 | } |
2668 | #endif | 2685 | #endif |
2669 | if (!probe_only[dev]) { | 2686 | if ((probe_only[dev] & 1) == 0) { |
2670 | err = azx_codec_configure(chip); | 2687 | err = azx_codec_configure(chip); |
2671 | if (err < 0) | 2688 | if (err < 0) |
2672 | goto out_free; | 2689 | goto out_free; |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index e9fdfc4b1c5..afbe314a5bf 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -71,9 +71,10 @@ struct ad198x_spec { | |||
71 | struct hda_input_mux private_imux; | 71 | struct hda_input_mux private_imux; |
72 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 72 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
73 | 73 | ||
74 | unsigned int jack_present :1; | 74 | unsigned int jack_present: 1; |
75 | unsigned int inv_jack_detect:1; /* inverted jack-detection */ | 75 | unsigned int inv_jack_detect: 1;/* inverted jack-detection */ |
76 | unsigned int inv_eapd:1; /* inverted EAPD implementation */ | 76 | unsigned int inv_eapd: 1; /* inverted EAPD implementation */ |
77 | unsigned int analog_beep: 1; /* analog beep input present */ | ||
77 | 78 | ||
78 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 79 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
79 | struct hda_loopback_check loopback; | 80 | struct hda_loopback_check loopback; |
@@ -165,6 +166,12 @@ static struct snd_kcontrol_new ad_beep_mixer[] = { | |||
165 | { } /* end */ | 166 | { } /* end */ |
166 | }; | 167 | }; |
167 | 168 | ||
169 | static struct snd_kcontrol_new ad_beep2_mixer[] = { | ||
170 | HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), | ||
171 | HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), | ||
172 | { } /* end */ | ||
173 | }; | ||
174 | |||
168 | #define set_beep_amp(spec, nid, idx, dir) \ | 175 | #define set_beep_amp(spec, nid, idx, dir) \ |
169 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ | 176 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ |
170 | #else | 177 | #else |
@@ -203,7 +210,8 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
203 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 210 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
204 | if (spec->beep_amp) { | 211 | if (spec->beep_amp) { |
205 | struct snd_kcontrol_new *knew; | 212 | struct snd_kcontrol_new *knew; |
206 | for (knew = ad_beep_mixer; knew->name; knew++) { | 213 | knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; |
214 | for ( ; knew->name; knew++) { | ||
207 | struct snd_kcontrol *kctl; | 215 | struct snd_kcontrol *kctl; |
208 | kctl = snd_ctl_new1(knew, codec); | 216 | kctl = snd_ctl_new1(knew, codec); |
209 | if (!kctl) | 217 | if (!kctl) |
@@ -3481,6 +3489,8 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | |||
3481 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | 3489 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), |
3482 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | 3490 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), |
3483 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | 3491 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), |
3492 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
3493 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
3484 | HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | 3494 | HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT), |
3485 | HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | 3495 | HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT), |
3486 | HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), | 3496 | HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), |
@@ -3522,6 +3532,8 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = { | |||
3522 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 3532 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
3523 | /* docking mic boost */ | 3533 | /* docking mic boost */ |
3524 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 3534 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
3535 | /* Analog PC Beeper - allow firmware/ACPI beeps */ | ||
3536 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a}, | ||
3525 | /* Analog mixer - docking mic; mute as default */ | 3537 | /* Analog mixer - docking mic; mute as default */ |
3526 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | 3538 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
3527 | /* enable EAPD bit */ | 3539 | /* enable EAPD bit */ |
@@ -3654,6 +3666,7 @@ static int patch_ad1984(struct hda_codec *codec) | |||
3654 | spec->input_mux = &ad1984_thinkpad_capture_source; | 3666 | spec->input_mux = &ad1984_thinkpad_capture_source; |
3655 | spec->mixers[0] = ad1984_thinkpad_mixers; | 3667 | spec->mixers[0] = ad1984_thinkpad_mixers; |
3656 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; | 3668 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; |
3669 | spec->analog_beep = 1; | ||
3657 | break; | 3670 | break; |
3658 | case AD1984_DELL_DESKTOP: | 3671 | case AD1984_DELL_DESKTOP: |
3659 | spec->multiout.dig_out_nid = 0; | 3672 | spec->multiout.dig_out_nid = 0; |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index feabb44c7ca..e863649d31f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -115,6 +115,7 @@ struct conexant_spec { | |||
115 | unsigned int port_d_mode; | 115 | unsigned int port_d_mode; |
116 | unsigned int dell_vostro:1; | 116 | unsigned int dell_vostro:1; |
117 | unsigned int ideapad:1; | 117 | unsigned int ideapad:1; |
118 | unsigned int thinkpad:1; | ||
118 | 119 | ||
119 | unsigned int ext_mic_present; | 120 | unsigned int ext_mic_present; |
120 | unsigned int recording; | 121 | unsigned int recording; |
@@ -1784,6 +1785,7 @@ static struct hda_verb cxt5051_init_verbs[] = { | |||
1784 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | 1785 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, |
1785 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | 1786 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, |
1786 | /* SPDIF route: PCM */ | 1787 | /* SPDIF route: PCM */ |
1788 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1787 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | 1789 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, |
1788 | /* EAPD */ | 1790 | /* EAPD */ |
1789 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 1791 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
@@ -1840,6 +1842,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | |||
1840 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | 1842 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, |
1841 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | 1843 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, |
1842 | /* SPDIF route: PCM */ | 1844 | /* SPDIF route: PCM */ |
1845 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */ | ||
1843 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | 1846 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, |
1844 | /* EAPD */ | 1847 | /* EAPD */ |
1845 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 1848 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
@@ -1911,7 +1914,7 @@ enum { | |||
1911 | CXT5051_LAPTOP, /* Laptops w/ EAPD support */ | 1914 | CXT5051_LAPTOP, /* Laptops w/ EAPD support */ |
1912 | CXT5051_HP, /* no docking */ | 1915 | CXT5051_HP, /* no docking */ |
1913 | CXT5051_HP_DV6736, /* HP without mic switch */ | 1916 | CXT5051_HP_DV6736, /* HP without mic switch */ |
1914 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ | 1917 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ |
1915 | CXT5051_F700, /* HP Compaq Presario F700 */ | 1918 | CXT5051_F700, /* HP Compaq Presario F700 */ |
1916 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ | 1919 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ |
1917 | CXT5051_MODELS | 1920 | CXT5051_MODELS |
@@ -2033,6 +2036,9 @@ static void cxt5066_update_speaker(struct hda_codec *codec) | |||
2033 | /* Port D (HP/LO) */ | 2036 | /* Port D (HP/LO) */ |
2034 | pinctl = ((spec->hp_present & 2) && spec->cur_eapd) | 2037 | pinctl = ((spec->hp_present & 2) && spec->cur_eapd) |
2035 | ? spec->port_d_mode : 0; | 2038 | ? spec->port_d_mode : 0; |
2039 | /* Mute if Port A is connected on Thinkpad */ | ||
2040 | if (spec->thinkpad && (spec->hp_present & 1)) | ||
2041 | pinctl = 0; | ||
2036 | snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 2042 | snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
2037 | pinctl); | 2043 | pinctl); |
2038 | 2044 | ||
@@ -2213,6 +2219,50 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) | |||
2213 | } | 2219 | } |
2214 | } | 2220 | } |
2215 | 2221 | ||
2222 | /* toggle input of built-in digital mic and mic jack appropriately | ||
2223 | order is: external mic -> dock mic -> interal mic */ | ||
2224 | static void cxt5066_thinkpad_automic(struct hda_codec *codec) | ||
2225 | { | ||
2226 | unsigned int ext_present, dock_present; | ||
2227 | |||
2228 | static struct hda_verb ext_mic_present[] = { | ||
2229 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | ||
2230 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, | ||
2231 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2232 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2233 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2234 | {} | ||
2235 | }; | ||
2236 | static struct hda_verb dock_mic_present[] = { | ||
2237 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | ||
2238 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | ||
2239 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2240 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2241 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2242 | {} | ||
2243 | }; | ||
2244 | static struct hda_verb ext_mic_absent[] = { | ||
2245 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, | ||
2246 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2247 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2248 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2249 | {} | ||
2250 | }; | ||
2251 | |||
2252 | ext_present = snd_hda_jack_detect(codec, 0x1b); | ||
2253 | dock_present = snd_hda_jack_detect(codec, 0x1a); | ||
2254 | if (ext_present) { | ||
2255 | snd_printdd("CXT5066: external microphone detected\n"); | ||
2256 | snd_hda_sequence_write(codec, ext_mic_present); | ||
2257 | } else if (dock_present) { | ||
2258 | snd_printdd("CXT5066: dock microphone detected\n"); | ||
2259 | snd_hda_sequence_write(codec, dock_mic_present); | ||
2260 | } else { | ||
2261 | snd_printdd("CXT5066: external microphone absent\n"); | ||
2262 | snd_hda_sequence_write(codec, ext_mic_absent); | ||
2263 | } | ||
2264 | } | ||
2265 | |||
2216 | /* mute internal speaker if HP is plugged */ | 2266 | /* mute internal speaker if HP is plugged */ |
2217 | static void cxt5066_hp_automute(struct hda_codec *codec) | 2267 | static void cxt5066_hp_automute(struct hda_codec *codec) |
2218 | { | 2268 | { |
@@ -2225,7 +2275,8 @@ static void cxt5066_hp_automute(struct hda_codec *codec) | |||
2225 | /* Port D */ | 2275 | /* Port D */ |
2226 | portD = snd_hda_jack_detect(codec, 0x1c); | 2276 | portD = snd_hda_jack_detect(codec, 0x1c); |
2227 | 2277 | ||
2228 | spec->hp_present = !!(portA | portD); | 2278 | spec->hp_present = !!(portA); |
2279 | spec->hp_present |= portD ? 2 : 0; | ||
2229 | snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", | 2280 | snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", |
2230 | portA, portD, spec->hp_present); | 2281 | portA, portD, spec->hp_present); |
2231 | cxt5066_update_speaker(codec); | 2282 | cxt5066_update_speaker(codec); |
@@ -2276,6 +2327,20 @@ static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) | |||
2276 | } | 2327 | } |
2277 | } | 2328 | } |
2278 | 2329 | ||
2330 | /* unsolicited event for jack sensing */ | ||
2331 | static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) | ||
2332 | { | ||
2333 | snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); | ||
2334 | switch (res >> 26) { | ||
2335 | case CONEXANT_HP_EVENT: | ||
2336 | cxt5066_hp_automute(codec); | ||
2337 | break; | ||
2338 | case CONEXANT_MIC_EVENT: | ||
2339 | cxt5066_thinkpad_automic(codec); | ||
2340 | break; | ||
2341 | } | ||
2342 | } | ||
2343 | |||
2279 | static const struct hda_input_mux cxt5066_analog_mic_boost = { | 2344 | static const struct hda_input_mux cxt5066_analog_mic_boost = { |
2280 | .num_items = 5, | 2345 | .num_items = 5, |
2281 | .items = { | 2346 | .items = { |
@@ -2294,7 +2359,7 @@ static void cxt5066_set_mic_boost(struct hda_codec *codec) | |||
2294 | AC_VERB_SET_AMP_GAIN_MUTE, | 2359 | AC_VERB_SET_AMP_GAIN_MUTE, |
2295 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | | 2360 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | |
2296 | cxt5066_analog_mic_boost.items[spec->mic_boost].index); | 2361 | cxt5066_analog_mic_boost.items[spec->mic_boost].index); |
2297 | if (spec->ideapad) { | 2362 | if (spec->ideapad || spec->thinkpad) { |
2298 | /* adjust the internal mic as well...it is not through 0x17 */ | 2363 | /* adjust the internal mic as well...it is not through 0x17 */ |
2299 | snd_hda_codec_write_cache(codec, 0x23, 0, | 2364 | snd_hda_codec_write_cache(codec, 0x23, 0, |
2300 | AC_VERB_SET_AMP_GAIN_MUTE, | 2365 | AC_VERB_SET_AMP_GAIN_MUTE, |
@@ -2782,6 +2847,64 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = { | |||
2782 | { } /* end */ | 2847 | { } /* end */ |
2783 | }; | 2848 | }; |
2784 | 2849 | ||
2850 | static struct hda_verb cxt5066_init_verbs_thinkpad[] = { | ||
2851 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | ||
2852 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ | ||
2853 | |||
2854 | /* Port G: internal speakers */ | ||
2855 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2856 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2857 | |||
2858 | /* Port A: HP, Amp */ | ||
2859 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2860 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2861 | |||
2862 | /* Port B: Mic Dock */ | ||
2863 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2864 | |||
2865 | /* Port C: Mic */ | ||
2866 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2867 | |||
2868 | /* Port D: HP Dock, Amp */ | ||
2869 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2870 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2871 | |||
2872 | /* DAC1 */ | ||
2873 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2874 | |||
2875 | /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ | ||
2876 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, | ||
2877 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2878 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, | ||
2879 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2880 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2881 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ | ||
2882 | |||
2883 | /* Audio input selector */ | ||
2884 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, | ||
2885 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ | ||
2886 | |||
2887 | /* SPDIF route: PCM */ | ||
2888 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2889 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2890 | |||
2891 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2892 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2893 | |||
2894 | /* internal microphone */ | ||
2895 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ | ||
2896 | |||
2897 | /* EAPD */ | ||
2898 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
2899 | |||
2900 | /* enable unsolicited events for Port A, B, C and D */ | ||
2901 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
2902 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
2903 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
2904 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
2905 | { } /* end */ | ||
2906 | }; | ||
2907 | |||
2785 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | 2908 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { |
2786 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 2909 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
2787 | { } /* end */ | 2910 | { } /* end */ |
@@ -2800,6 +2923,8 @@ static int cxt5066_init(struct hda_codec *codec) | |||
2800 | cxt5066_vostro_automic(codec); | 2923 | cxt5066_vostro_automic(codec); |
2801 | else if (spec->ideapad) | 2924 | else if (spec->ideapad) |
2802 | cxt5066_ideapad_automic(codec); | 2925 | cxt5066_ideapad_automic(codec); |
2926 | else if (spec->thinkpad) | ||
2927 | cxt5066_thinkpad_automic(codec); | ||
2803 | } | 2928 | } |
2804 | cxt5066_set_mic_boost(codec); | 2929 | cxt5066_set_mic_boost(codec); |
2805 | return 0; | 2930 | return 0; |
@@ -2821,20 +2946,22 @@ static int cxt5066_olpc_init(struct hda_codec *codec) | |||
2821 | } | 2946 | } |
2822 | 2947 | ||
2823 | enum { | 2948 | enum { |
2824 | CXT5066_LAPTOP, /* Laptops w/ EAPD support */ | 2949 | CXT5066_LAPTOP, /* Laptops w/ EAPD support */ |
2825 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ | 2950 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ |
2826 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ | 2951 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ |
2827 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ | 2952 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ |
2828 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ | 2953 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ |
2954 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ | ||
2829 | CXT5066_MODELS | 2955 | CXT5066_MODELS |
2830 | }; | 2956 | }; |
2831 | 2957 | ||
2832 | static const char *cxt5066_models[CXT5066_MODELS] = { | 2958 | static const char *cxt5066_models[CXT5066_MODELS] = { |
2833 | [CXT5066_LAPTOP] = "laptop", | 2959 | [CXT5066_LAPTOP] = "laptop", |
2834 | [CXT5066_DELL_LAPTOP] = "dell-laptop", | 2960 | [CXT5066_DELL_LAPTOP] = "dell-laptop", |
2835 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", | 2961 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", |
2836 | [CXT5066_DELL_VOSTO] = "dell-vostro", | 2962 | [CXT5066_DELL_VOSTO] = "dell-vostro", |
2837 | [CXT5066_IDEAPAD] = "ideapad", | 2963 | [CXT5066_IDEAPAD] = "ideapad", |
2964 | [CXT5066_THINKPAD] = "thinkpad", | ||
2838 | }; | 2965 | }; |
2839 | 2966 | ||
2840 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | 2967 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { |
@@ -2849,6 +2976,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | |||
2849 | SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), | 2976 | SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), |
2850 | SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), | 2977 | SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), |
2851 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), | 2978 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), |
2979 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), | ||
2852 | {} | 2980 | {} |
2853 | }; | 2981 | }; |
2854 | 2982 | ||
@@ -2956,6 +3084,22 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2956 | /* input source automatically selected */ | 3084 | /* input source automatically selected */ |
2957 | spec->input_mux = NULL; | 3085 | spec->input_mux = NULL; |
2958 | break; | 3086 | break; |
3087 | case CXT5066_THINKPAD: | ||
3088 | codec->patch_ops.init = cxt5066_init; | ||
3089 | codec->patch_ops.unsol_event = cxt5066_thinkpad_event; | ||
3090 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | ||
3091 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | ||
3092 | spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; | ||
3093 | spec->thinkpad = 1; | ||
3094 | spec->port_d_mode = PIN_OUT; | ||
3095 | spec->mic_boost = 2; /* default 20dB gain */ | ||
3096 | |||
3097 | /* no S/PDIF out */ | ||
3098 | spec->multiout.dig_out_nid = 0; | ||
3099 | |||
3100 | /* input source automatically selected */ | ||
3101 | spec->input_mux = NULL; | ||
3102 | break; | ||
2959 | } | 3103 | } |
2960 | 3104 | ||
2961 | return 0; | 3105 | return 0; |
@@ -2975,6 +3119,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
2975 | .patch = patch_cxt5066 }, | 3119 | .patch = patch_cxt5066 }, |
2976 | { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", | 3120 | { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", |
2977 | .patch = patch_cxt5066 }, | 3121 | .patch = patch_cxt5066 }, |
3122 | { .id = 0x14f15069, .name = "CX20585", | ||
3123 | .patch = patch_cxt5066 }, | ||
2978 | {} /* terminator */ | 3124 | {} /* terminator */ |
2979 | }; | 3125 | }; |
2980 | 3126 | ||
@@ -2983,6 +3129,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15047"); | |||
2983 | MODULE_ALIAS("snd-hda-codec-id:14f15051"); | 3129 | MODULE_ALIAS("snd-hda-codec-id:14f15051"); |
2984 | MODULE_ALIAS("snd-hda-codec-id:14f15066"); | 3130 | MODULE_ALIAS("snd-hda-codec-id:14f15066"); |
2985 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); | 3131 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); |
3132 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); | ||
2986 | 3133 | ||
2987 | MODULE_LICENSE("GPL"); | 3134 | MODULE_LICENSE("GPL"); |
2988 | MODULE_DESCRIPTION("Conexant HD-audio codec"); | 3135 | MODULE_DESCRIPTION("Conexant HD-audio codec"); |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2c2bafbf025..86067ee7863 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -766,7 +766,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) | |||
766 | if (spec->num_pins >= MAX_HDMI_PINS) { | 766 | if (spec->num_pins >= MAX_HDMI_PINS) { |
767 | snd_printk(KERN_WARNING | 767 | snd_printk(KERN_WARNING |
768 | "HDMI: no space for pin %d\n", pin_nid); | 768 | "HDMI: no space for pin %d\n", pin_nid); |
769 | return -EINVAL; | 769 | return -E2BIG; |
770 | } | 770 | } |
771 | 771 | ||
772 | hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); | 772 | hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); |
@@ -788,7 +788,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) | |||
788 | if (spec->num_cvts >= MAX_HDMI_CVTS) { | 788 | if (spec->num_cvts >= MAX_HDMI_CVTS) { |
789 | snd_printk(KERN_WARNING | 789 | snd_printk(KERN_WARNING |
790 | "HDMI: no space for converter %d\n", nid); | 790 | "HDMI: no space for converter %d\n", nid); |
791 | return -EINVAL; | 791 | return -E2BIG; |
792 | } | 792 | } |
793 | 793 | ||
794 | spec->cvt[spec->num_cvts] = nid; | 794 | spec->cvt[spec->num_cvts] = nid; |
@@ -820,15 +820,13 @@ static int hdmi_parse_codec(struct hda_codec *codec) | |||
820 | 820 | ||
821 | switch (type) { | 821 | switch (type) { |
822 | case AC_WID_AUD_OUT: | 822 | case AC_WID_AUD_OUT: |
823 | if (hdmi_add_cvt(codec, nid) < 0) | 823 | hdmi_add_cvt(codec, nid); |
824 | return -EINVAL; | ||
825 | break; | 824 | break; |
826 | case AC_WID_PIN: | 825 | case AC_WID_PIN: |
827 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | 826 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); |
828 | if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) | 827 | if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) |
829 | continue; | 828 | continue; |
830 | if (hdmi_add_pin(codec, nid) < 0) | 829 | hdmi_add_pin(codec, nid); |
831 | return -EINVAL; | ||
832 | break; | 830 | break; |
833 | } | 831 | } |
834 | } | 832 | } |
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 88d035104cc..b81d23e42ac 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c | |||
@@ -40,7 +40,7 @@ | |||
40 | * | 40 | * |
41 | * The HDA correspondence of pipes/ports are converter/pin nodes. | 41 | * The HDA correspondence of pipes/ports are converter/pin nodes. |
42 | */ | 42 | */ |
43 | #define MAX_HDMI_CVTS 2 | 43 | #define MAX_HDMI_CVTS 3 |
44 | #define MAX_HDMI_PINS 3 | 44 | #define MAX_HDMI_PINS 3 |
45 | 45 | ||
46 | #include "patch_hdmi.c" | 46 | #include "patch_hdmi.c" |
@@ -48,6 +48,7 @@ | |||
48 | static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = { | 48 | static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = { |
49 | "INTEL HDMI 0", | 49 | "INTEL HDMI 0", |
50 | "INTEL HDMI 1", | 50 | "INTEL HDMI 1", |
51 | "INTEL HDMI 2", | ||
51 | }; | 52 | }; |
52 | 53 | ||
53 | /* | 54 | /* |
@@ -185,14 +186,15 @@ static int patch_intel_hdmi(struct hda_codec *codec) | |||
185 | } | 186 | } |
186 | 187 | ||
187 | static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { | 188 | static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { |
188 | { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, | 189 | { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_intel_hdmi }, |
189 | { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, | 190 | { .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_intel_hdmi }, |
190 | { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, | 191 | { .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_intel_hdmi }, |
191 | { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, | 192 | { .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_intel_hdmi }, |
192 | { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, | 193 | { .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi }, |
193 | { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi }, | 194 | { .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi }, |
194 | { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, | 195 | { .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_intel_hdmi }, |
195 | {} /* terminator */ | 196 | { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, |
197 | {} /* terminator */ | ||
196 | }; | 198 | }; |
197 | 199 | ||
198 | MODULE_ALIAS("snd-hda-codec-id:808629fb"); | 200 | MODULE_ALIAS("snd-hda-codec-id:808629fb"); |
@@ -200,6 +202,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801"); | |||
200 | MODULE_ALIAS("snd-hda-codec-id:80862802"); | 202 | MODULE_ALIAS("snd-hda-codec-id:80862802"); |
201 | MODULE_ALIAS("snd-hda-codec-id:80862803"); | 203 | MODULE_ALIAS("snd-hda-codec-id:80862803"); |
202 | MODULE_ALIAS("snd-hda-codec-id:80862804"); | 204 | MODULE_ALIAS("snd-hda-codec-id:80862804"); |
205 | MODULE_ALIAS("snd-hda-codec-id:80862805"); | ||
203 | MODULE_ALIAS("snd-hda-codec-id:80860054"); | 206 | MODULE_ALIAS("snd-hda-codec-id:80860054"); |
204 | MODULE_ALIAS("snd-hda-codec-id:10951392"); | 207 | MODULE_ALIAS("snd-hda-codec-id:10951392"); |
205 | 208 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 886d8e46bb3..53538b0f999 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -276,6 +276,18 @@ struct alc_mic_route { | |||
276 | 276 | ||
277 | #define MUX_IDX_UNDEF ((unsigned char)-1) | 277 | #define MUX_IDX_UNDEF ((unsigned char)-1) |
278 | 278 | ||
279 | struct alc_customize_define { | ||
280 | unsigned int sku_cfg; | ||
281 | unsigned char port_connectivity; | ||
282 | unsigned char check_sum; | ||
283 | unsigned char customization; | ||
284 | unsigned char external_amp; | ||
285 | unsigned int enable_pcbeep:1; | ||
286 | unsigned int platform_type:1; | ||
287 | unsigned int swap:1; | ||
288 | unsigned int override:1; | ||
289 | }; | ||
290 | |||
279 | struct alc_spec { | 291 | struct alc_spec { |
280 | /* codec parameterization */ | 292 | /* codec parameterization */ |
281 | struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ | 293 | struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ |
@@ -333,6 +345,7 @@ struct alc_spec { | |||
333 | 345 | ||
334 | /* dynamic controls, init_verbs and input_mux */ | 346 | /* dynamic controls, init_verbs and input_mux */ |
335 | struct auto_pin_cfg autocfg; | 347 | struct auto_pin_cfg autocfg; |
348 | struct alc_customize_define cdefine; | ||
336 | struct snd_array kctls; | 349 | struct snd_array kctls; |
337 | struct hda_input_mux private_imux[3]; | 350 | struct hda_input_mux private_imux[3]; |
338 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 351 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
@@ -1248,6 +1261,62 @@ static void alc_init_auto_mic(struct hda_codec *codec) | |||
1248 | spec->unsol_event = alc_sku_unsol_event; | 1261 | spec->unsol_event = alc_sku_unsol_event; |
1249 | } | 1262 | } |
1250 | 1263 | ||
1264 | static int alc_auto_parse_customize_define(struct hda_codec *codec) | ||
1265 | { | ||
1266 | unsigned int ass, tmp, i; | ||
1267 | unsigned nid = 0; | ||
1268 | struct alc_spec *spec = codec->spec; | ||
1269 | |||
1270 | ass = codec->subsystem_id & 0xffff; | ||
1271 | if (ass != codec->bus->pci->subsystem_device && (ass & 1)) | ||
1272 | goto do_sku; | ||
1273 | |||
1274 | nid = 0x1d; | ||
1275 | if (codec->vendor_id == 0x10ec0260) | ||
1276 | nid = 0x17; | ||
1277 | ass = snd_hda_codec_get_pincfg(codec, nid); | ||
1278 | |||
1279 | if (!(ass & 1)) { | ||
1280 | printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n", | ||
1281 | codec->chip_name, ass); | ||
1282 | return -1; | ||
1283 | } | ||
1284 | |||
1285 | /* check sum */ | ||
1286 | tmp = 0; | ||
1287 | for (i = 1; i < 16; i++) { | ||
1288 | if ((ass >> i) & 1) | ||
1289 | tmp++; | ||
1290 | } | ||
1291 | if (((ass >> 16) & 0xf) != tmp) | ||
1292 | return -1; | ||
1293 | |||
1294 | spec->cdefine.port_connectivity = ass >> 30; | ||
1295 | spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20; | ||
1296 | spec->cdefine.check_sum = (ass >> 16) & 0xf; | ||
1297 | spec->cdefine.customization = ass >> 8; | ||
1298 | do_sku: | ||
1299 | spec->cdefine.sku_cfg = ass; | ||
1300 | spec->cdefine.external_amp = (ass & 0x38) >> 3; | ||
1301 | spec->cdefine.platform_type = (ass & 0x4) >> 2; | ||
1302 | spec->cdefine.swap = (ass & 0x2) >> 1; | ||
1303 | spec->cdefine.override = ass & 0x1; | ||
1304 | |||
1305 | snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n", | ||
1306 | nid, spec->cdefine.sku_cfg); | ||
1307 | snd_printd("SKU: port_connectivity=0x%x\n", | ||
1308 | spec->cdefine.port_connectivity); | ||
1309 | snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep); | ||
1310 | snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum); | ||
1311 | snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization); | ||
1312 | snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp); | ||
1313 | snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type); | ||
1314 | snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap); | ||
1315 | snd_printd("SKU: override=0x%x\n", spec->cdefine.override); | ||
1316 | |||
1317 | return 0; | ||
1318 | } | ||
1319 | |||
1251 | /* check subsystem ID and set up device-specific initialization; | 1320 | /* check subsystem ID and set up device-specific initialization; |
1252 | * return 1 if initialized, 0 if invalid SSID | 1321 | * return 1 if initialized, 0 if invalid SSID |
1253 | */ | 1322 | */ |
@@ -3415,6 +3484,10 @@ static int alc_init(struct hda_codec *codec) | |||
3415 | if (spec->init_hook) | 3484 | if (spec->init_hook) |
3416 | spec->init_hook(codec); | 3485 | spec->init_hook(codec); |
3417 | 3486 | ||
3487 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3488 | if (codec->patch_ops.check_power_status) | ||
3489 | codec->patch_ops.check_power_status(codec, 0x01); | ||
3490 | #endif | ||
3418 | return 0; | 3491 | return 0; |
3419 | } | 3492 | } |
3420 | 3493 | ||
@@ -3775,6 +3848,10 @@ static int alc_resume(struct hda_codec *codec) | |||
3775 | codec->patch_ops.init(codec); | 3848 | codec->patch_ops.init(codec); |
3776 | snd_hda_codec_resume_amp(codec); | 3849 | snd_hda_codec_resume_amp(codec); |
3777 | snd_hda_codec_resume_cache(codec); | 3850 | snd_hda_codec_resume_cache(codec); |
3851 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3852 | if (codec->patch_ops.check_power_status) | ||
3853 | codec->patch_ops.check_power_status(codec, 0x01); | ||
3854 | #endif | ||
3778 | return 0; | 3855 | return 0; |
3779 | } | 3856 | } |
3780 | #endif | 3857 | #endif |
@@ -3797,6 +3874,17 @@ static struct hda_codec_ops alc_patch_ops = { | |||
3797 | .reboot_notify = alc_shutup, | 3874 | .reboot_notify = alc_shutup, |
3798 | }; | 3875 | }; |
3799 | 3876 | ||
3877 | /* replace the codec chip_name with the given string */ | ||
3878 | static int alc_codec_rename(struct hda_codec *codec, const char *name) | ||
3879 | { | ||
3880 | kfree(codec->chip_name); | ||
3881 | codec->chip_name = kstrdup(name, GFP_KERNEL); | ||
3882 | if (!codec->chip_name) { | ||
3883 | alc_free(codec); | ||
3884 | return -ENOMEM; | ||
3885 | } | ||
3886 | return 0; | ||
3887 | } | ||
3800 | 3888 | ||
3801 | /* | 3889 | /* |
3802 | * Test configuration for debugging | 3890 | * Test configuration for debugging |
@@ -10189,21 +10277,20 @@ static int alc882_auto_create_input_ctls(struct hda_codec *codec, | |||
10189 | 10277 | ||
10190 | static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, | 10278 | static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, |
10191 | hda_nid_t nid, int pin_type, | 10279 | hda_nid_t nid, int pin_type, |
10192 | int dac_idx) | 10280 | hda_nid_t dac) |
10193 | { | 10281 | { |
10194 | /* set as output */ | ||
10195 | struct alc_spec *spec = codec->spec; | ||
10196 | int idx; | 10282 | int idx; |
10197 | 10283 | ||
10284 | /* set as output */ | ||
10198 | alc_set_pin_output(codec, nid, pin_type); | 10285 | alc_set_pin_output(codec, nid, pin_type); |
10199 | if (dac_idx >= spec->multiout.num_dacs) | 10286 | |
10200 | return; | 10287 | if (dac == 0x25) |
10201 | if (spec->multiout.dac_nids[dac_idx] == 0x25) | ||
10202 | idx = 4; | 10288 | idx = 4; |
10289 | else if (dac >= 0x02 && dac <= 0x05) | ||
10290 | idx = dac - 2; | ||
10203 | else | 10291 | else |
10204 | idx = spec->multiout.dac_nids[dac_idx] - 2; | 10292 | return; |
10205 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); | 10293 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); |
10206 | |||
10207 | } | 10294 | } |
10208 | 10295 | ||
10209 | static void alc882_auto_init_multi_out(struct hda_codec *codec) | 10296 | static void alc882_auto_init_multi_out(struct hda_codec *codec) |
@@ -10216,22 +10303,29 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec) | |||
10216 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 10303 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
10217 | if (nid) | 10304 | if (nid) |
10218 | alc882_auto_set_output_and_unmute(codec, nid, pin_type, | 10305 | alc882_auto_set_output_and_unmute(codec, nid, pin_type, |
10219 | i); | 10306 | spec->multiout.dac_nids[i]); |
10220 | } | 10307 | } |
10221 | } | 10308 | } |
10222 | 10309 | ||
10223 | static void alc882_auto_init_hp_out(struct hda_codec *codec) | 10310 | static void alc882_auto_init_hp_out(struct hda_codec *codec) |
10224 | { | 10311 | { |
10225 | struct alc_spec *spec = codec->spec; | 10312 | struct alc_spec *spec = codec->spec; |
10226 | hda_nid_t pin; | 10313 | hda_nid_t pin, dac; |
10227 | 10314 | ||
10228 | pin = spec->autocfg.hp_pins[0]; | 10315 | pin = spec->autocfg.hp_pins[0]; |
10229 | if (pin) /* connect to front */ | 10316 | if (pin) { |
10230 | /* use dac 0 */ | 10317 | dac = spec->multiout.hp_nid; |
10231 | alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 10318 | if (!dac) |
10319 | dac = spec->multiout.dac_nids[0]; /* to front */ | ||
10320 | alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); | ||
10321 | } | ||
10232 | pin = spec->autocfg.speaker_pins[0]; | 10322 | pin = spec->autocfg.speaker_pins[0]; |
10233 | if (pin) | 10323 | if (pin) { |
10234 | alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); | 10324 | dac = spec->multiout.extra_out_nid[0]; |
10325 | if (!dac) | ||
10326 | dac = spec->multiout.dac_nids[0]; /* to front */ | ||
10327 | alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); | ||
10328 | } | ||
10235 | } | 10329 | } |
10236 | 10330 | ||
10237 | static void alc882_auto_init_analog_input(struct hda_codec *codec) | 10331 | static void alc882_auto_init_analog_input(struct hda_codec *codec) |
@@ -10347,15 +10441,15 @@ static int alc882_parse_auto_config(struct hda_codec *codec) | |||
10347 | err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); | 10441 | err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); |
10348 | if (err < 0) | 10442 | if (err < 0) |
10349 | return err; | 10443 | return err; |
10444 | err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], | ||
10445 | "Headphone"); | ||
10446 | if (err < 0) | ||
10447 | return err; | ||
10350 | err = alc880_auto_create_extra_out(spec, | 10448 | err = alc880_auto_create_extra_out(spec, |
10351 | spec->autocfg.speaker_pins[0], | 10449 | spec->autocfg.speaker_pins[0], |
10352 | "Speaker"); | 10450 | "Speaker"); |
10353 | if (err < 0) | 10451 | if (err < 0) |
10354 | return err; | 10452 | return err; |
10355 | err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], | ||
10356 | "Headphone"); | ||
10357 | if (err < 0) | ||
10358 | return err; | ||
10359 | err = alc882_auto_create_input_ctls(codec, &spec->autocfg); | 10453 | err = alc882_auto_create_input_ctls(codec, &spec->autocfg); |
10360 | if (err < 0) | 10454 | if (err < 0) |
10361 | return err; | 10455 | return err; |
@@ -10425,6 +10519,8 @@ static int patch_alc882(struct hda_codec *codec) | |||
10425 | 10519 | ||
10426 | codec->spec = spec; | 10520 | codec->spec = spec; |
10427 | 10521 | ||
10522 | alc_auto_parse_customize_define(codec); | ||
10523 | |||
10428 | switch (codec->vendor_id) { | 10524 | switch (codec->vendor_id) { |
10429 | case 0x10ec0882: | 10525 | case 0x10ec0882: |
10430 | case 0x10ec0885: | 10526 | case 0x10ec0885: |
@@ -10484,9 +10580,6 @@ static int patch_alc882(struct hda_codec *codec) | |||
10484 | spec->stream_digital_playback = &alc882_pcm_digital_playback; | 10580 | spec->stream_digital_playback = &alc882_pcm_digital_playback; |
10485 | spec->stream_digital_capture = &alc882_pcm_digital_capture; | 10581 | spec->stream_digital_capture = &alc882_pcm_digital_capture; |
10486 | 10582 | ||
10487 | if (codec->vendor_id == 0x10ec0888) | ||
10488 | spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ | ||
10489 | |||
10490 | if (!spec->adc_nids && spec->input_mux) { | 10583 | if (!spec->adc_nids && spec->input_mux) { |
10491 | int i, j; | 10584 | int i, j; |
10492 | spec->num_adc_nids = 0; | 10585 | spec->num_adc_nids = 0; |
@@ -10521,7 +10614,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
10521 | } | 10614 | } |
10522 | 10615 | ||
10523 | set_capture_mixer(codec); | 10616 | set_capture_mixer(codec); |
10524 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); | 10617 | |
10618 | if (spec->cdefine.enable_pcbeep) | ||
10619 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); | ||
10525 | 10620 | ||
10526 | if (board_config == ALC882_AUTO) | 10621 | if (board_config == ALC882_AUTO) |
10527 | alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0); | 10622 | alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0); |
@@ -12308,6 +12403,7 @@ static int patch_alc262(struct hda_codec *codec) | |||
12308 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); | 12403 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); |
12309 | } | 12404 | } |
12310 | #endif | 12405 | #endif |
12406 | alc_auto_parse_customize_define(codec); | ||
12311 | 12407 | ||
12312 | alc_fix_pll_init(codec, 0x20, 0x0a, 10); | 12408 | alc_fix_pll_init(codec, 0x20, 0x0a, 10); |
12313 | 12409 | ||
@@ -12386,7 +12482,7 @@ static int patch_alc262(struct hda_codec *codec) | |||
12386 | } | 12482 | } |
12387 | if (!spec->cap_mixer && !spec->no_analog) | 12483 | if (!spec->cap_mixer && !spec->no_analog) |
12388 | set_capture_mixer(codec); | 12484 | set_capture_mixer(codec); |
12389 | if (!spec->no_analog) | 12485 | if (!spec->no_analog && spec->cdefine.enable_pcbeep) |
12390 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); | 12486 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); |
12391 | 12487 | ||
12392 | spec->vmaster_nid = 0x0c; | 12488 | spec->vmaster_nid = 0x0c; |
@@ -14005,6 +14101,35 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_capture = { | |||
14005 | /* NID is set in alc_build_pcms */ | 14101 | /* NID is set in alc_build_pcms */ |
14006 | }; | 14102 | }; |
14007 | 14103 | ||
14104 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
14105 | static int alc269_mic2_for_mute_led(struct hda_codec *codec) | ||
14106 | { | ||
14107 | switch (codec->subsystem_id) { | ||
14108 | case 0x103c1586: | ||
14109 | return 1; | ||
14110 | } | ||
14111 | return 0; | ||
14112 | } | ||
14113 | |||
14114 | static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) | ||
14115 | { | ||
14116 | /* update mute-LED according to the speaker mute state */ | ||
14117 | if (nid == 0x01 || nid == 0x14) { | ||
14118 | int pinval; | ||
14119 | if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & | ||
14120 | HDA_AMP_MUTE) | ||
14121 | pinval = 0x24; | ||
14122 | else | ||
14123 | pinval = 0x20; | ||
14124 | /* mic2 vref pin is used for mute LED control */ | ||
14125 | snd_hda_codec_update_cache(codec, 0x19, 0, | ||
14126 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
14127 | pinval); | ||
14128 | } | ||
14129 | return alc_check_power_status(codec, nid); | ||
14130 | } | ||
14131 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | ||
14132 | |||
14008 | /* | 14133 | /* |
14009 | * BIOS auto configuration | 14134 | * BIOS auto configuration |
14010 | */ | 14135 | */ |
@@ -14082,7 +14207,7 @@ enum { | |||
14082 | ALC269_FIXUP_SONY_VAIO, | 14207 | ALC269_FIXUP_SONY_VAIO, |
14083 | }; | 14208 | }; |
14084 | 14209 | ||
14085 | const static struct hda_verb alc269_sony_vaio_fixup_verbs[] = { | 14210 | static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = { |
14086 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, | 14211 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, |
14087 | {} | 14212 | {} |
14088 | }; | 14213 | }; |
@@ -14290,17 +14415,17 @@ static int patch_alc269(struct hda_codec *codec) | |||
14290 | 14415 | ||
14291 | codec->spec = spec; | 14416 | codec->spec = spec; |
14292 | 14417 | ||
14293 | alc_fix_pll_init(codec, 0x20, 0x04, 15); | 14418 | alc_auto_parse_customize_define(codec); |
14294 | 14419 | ||
14295 | if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ | 14420 | if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ |
14296 | kfree(codec->chip_name); | 14421 | if (codec->bus->pci->subsystem_vendor == 0x1025 && |
14297 | codec->chip_name = kstrdup("ALC259", GFP_KERNEL); | 14422 | spec->cdefine.platform_type == 1) |
14298 | if (!codec->chip_name) { | 14423 | alc_codec_rename(codec, "ALC271X"); |
14299 | alc_free(codec); | 14424 | else |
14300 | return -ENOMEM; | 14425 | alc_codec_rename(codec, "ALC259"); |
14301 | } | ||
14302 | is_alc269vb = 1; | 14426 | is_alc269vb = 1; |
14303 | } | 14427 | } else |
14428 | alc_fix_pll_init(codec, 0x20, 0x04, 15); | ||
14304 | 14429 | ||
14305 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, | 14430 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, |
14306 | alc269_models, | 14431 | alc269_models, |
@@ -14365,7 +14490,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
14365 | 14490 | ||
14366 | if (!spec->cap_mixer) | 14491 | if (!spec->cap_mixer) |
14367 | set_capture_mixer(codec); | 14492 | set_capture_mixer(codec); |
14368 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); | 14493 | if (spec->cdefine.enable_pcbeep) |
14494 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); | ||
14369 | 14495 | ||
14370 | if (board_config == ALC269_AUTO) | 14496 | if (board_config == ALC269_AUTO) |
14371 | alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0); | 14497 | alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0); |
@@ -14378,6 +14504,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
14378 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 14504 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
14379 | if (!spec->loopback.amplist) | 14505 | if (!spec->loopback.amplist) |
14380 | spec->loopback.amplist = alc269_loopbacks; | 14506 | spec->loopback.amplist = alc269_loopbacks; |
14507 | if (alc269_mic2_for_mute_led(codec)) | ||
14508 | codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; | ||
14381 | #endif | 14509 | #endif |
14382 | 14510 | ||
14383 | return 0; | 14511 | return 0; |
@@ -18525,16 +18653,16 @@ static int patch_alc662(struct hda_codec *codec) | |||
18525 | 18653 | ||
18526 | codec->spec = spec; | 18654 | codec->spec = spec; |
18527 | 18655 | ||
18656 | alc_auto_parse_customize_define(codec); | ||
18657 | |||
18528 | alc_fix_pll_init(codec, 0x20, 0x04, 15); | 18658 | alc_fix_pll_init(codec, 0x20, 0x04, 15); |
18529 | 18659 | ||
18530 | if (alc_read_coef_idx(codec, 0)==0x8020){ | 18660 | if (alc_read_coef_idx(codec, 0) == 0x8020) |
18531 | kfree(codec->chip_name); | 18661 | alc_codec_rename(codec, "ALC661"); |
18532 | codec->chip_name = kstrdup("ALC661", GFP_KERNEL); | 18662 | else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) && |
18533 | if (!codec->chip_name) { | 18663 | codec->bus->pci->subsystem_vendor == 0x1025 && |
18534 | alc_free(codec); | 18664 | spec->cdefine.platform_type == 1) |
18535 | return -ENOMEM; | 18665 | alc_codec_rename(codec, "ALC272X"); |
18536 | } | ||
18537 | } | ||
18538 | 18666 | ||
18539 | board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, | 18667 | board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, |
18540 | alc662_models, | 18668 | alc662_models, |
@@ -18584,18 +18712,20 @@ static int patch_alc662(struct hda_codec *codec) | |||
18584 | if (!spec->cap_mixer) | 18712 | if (!spec->cap_mixer) |
18585 | set_capture_mixer(codec); | 18713 | set_capture_mixer(codec); |
18586 | 18714 | ||
18587 | switch (codec->vendor_id) { | 18715 | if (spec->cdefine.enable_pcbeep) { |
18588 | case 0x10ec0662: | 18716 | switch (codec->vendor_id) { |
18589 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); | 18717 | case 0x10ec0662: |
18590 | break; | 18718 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); |
18591 | case 0x10ec0272: | 18719 | break; |
18592 | case 0x10ec0663: | 18720 | case 0x10ec0272: |
18593 | case 0x10ec0665: | 18721 | case 0x10ec0663: |
18594 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); | 18722 | case 0x10ec0665: |
18595 | break; | 18723 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); |
18596 | case 0x10ec0273: | 18724 | break; |
18597 | set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); | 18725 | case 0x10ec0273: |
18598 | break; | 18726 | set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); |
18727 | break; | ||
18728 | } | ||
18599 | } | 18729 | } |
18600 | spec->vmaster_nid = 0x02; | 18730 | spec->vmaster_nid = 0x02; |
18601 | 18731 | ||
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 9e66f6d306f..2f6252266a0 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c | |||
@@ -1956,11 +1956,10 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) | |||
1956 | return 0; | 1956 | return 0; |
1957 | } | 1957 | } |
1958 | 1958 | ||
1959 | |||
1960 | /* | 1959 | /* |
1961 | * initialize the chip | 1960 | * reset the chip |
1962 | */ | 1961 | */ |
1963 | static int __devinit aureon_init(struct snd_ice1712 *ice) | 1962 | static int aureon_reset(struct snd_ice1712 *ice) |
1964 | { | 1963 | { |
1965 | static const unsigned short wm_inits_aureon[] = { | 1964 | static const unsigned short wm_inits_aureon[] = { |
1966 | /* These come first to reduce init pop noise */ | 1965 | /* These come first to reduce init pop noise */ |
@@ -2047,30 +2046,10 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2047 | 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ | 2046 | 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ |
2048 | (unsigned short)-1 | 2047 | (unsigned short)-1 |
2049 | }; | 2048 | }; |
2050 | struct aureon_spec *spec; | ||
2051 | unsigned int tmp; | 2049 | unsigned int tmp; |
2052 | const unsigned short *p; | 2050 | const unsigned short *p; |
2053 | int err, i; | 2051 | int err; |
2054 | 2052 | struct aureon_spec *spec = ice->spec; | |
2055 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
2056 | if (!spec) | ||
2057 | return -ENOMEM; | ||
2058 | ice->spec = spec; | ||
2059 | |||
2060 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { | ||
2061 | ice->num_total_dacs = 6; | ||
2062 | ice->num_total_adcs = 2; | ||
2063 | } else { | ||
2064 | /* aureon 7.1 and prodigy 7.1 */ | ||
2065 | ice->num_total_dacs = 8; | ||
2066 | ice->num_total_adcs = 2; | ||
2067 | } | ||
2068 | |||
2069 | /* to remeber the register values of CS8415 */ | ||
2070 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
2071 | if (!ice->akm) | ||
2072 | return -ENOMEM; | ||
2073 | ice->akm_codecs = 1; | ||
2074 | 2053 | ||
2075 | err = aureon_ac97_init(ice); | 2054 | err = aureon_ac97_init(ice); |
2076 | if (err != 0) | 2055 | if (err != 0) |
@@ -2118,6 +2097,61 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2118 | /* initialize PCA9554 pin directions & set default input */ | 2097 | /* initialize PCA9554 pin directions & set default input */ |
2119 | aureon_pca9554_write(ice, PCA9554_DIR, 0x00); | 2098 | aureon_pca9554_write(ice, PCA9554_DIR, 0x00); |
2120 | aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ | 2099 | aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ |
2100 | return 0; | ||
2101 | } | ||
2102 | |||
2103 | /* | ||
2104 | * suspend/resume | ||
2105 | */ | ||
2106 | #ifdef CONFIG_PM | ||
2107 | static int aureon_resume(struct snd_ice1712 *ice) | ||
2108 | { | ||
2109 | struct aureon_spec *spec = ice->spec; | ||
2110 | int err, i; | ||
2111 | |||
2112 | err = aureon_reset(ice); | ||
2113 | if (err != 0) | ||
2114 | return err; | ||
2115 | |||
2116 | /* workaround for poking volume with alsamixer after resume: | ||
2117 | * just set stored volume again */ | ||
2118 | for (i = 0; i < ice->num_total_dacs; i++) | ||
2119 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); | ||
2120 | return 0; | ||
2121 | } | ||
2122 | #endif | ||
2123 | |||
2124 | /* | ||
2125 | * initialize the chip | ||
2126 | */ | ||
2127 | static int __devinit aureon_init(struct snd_ice1712 *ice) | ||
2128 | { | ||
2129 | struct aureon_spec *spec; | ||
2130 | int i, err; | ||
2131 | |||
2132 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
2133 | if (!spec) | ||
2134 | return -ENOMEM; | ||
2135 | ice->spec = spec; | ||
2136 | |||
2137 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { | ||
2138 | ice->num_total_dacs = 6; | ||
2139 | ice->num_total_adcs = 2; | ||
2140 | } else { | ||
2141 | /* aureon 7.1 and prodigy 7.1 */ | ||
2142 | ice->num_total_dacs = 8; | ||
2143 | ice->num_total_adcs = 2; | ||
2144 | } | ||
2145 | |||
2146 | /* to remeber the register values of CS8415 */ | ||
2147 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
2148 | if (!ice->akm) | ||
2149 | return -ENOMEM; | ||
2150 | ice->akm_codecs = 1; | ||
2151 | |||
2152 | err = aureon_reset(ice); | ||
2153 | if (err != 0) | ||
2154 | return err; | ||
2121 | 2155 | ||
2122 | spec->master[0] = WM_VOL_MUTE; | 2156 | spec->master[0] = WM_VOL_MUTE; |
2123 | spec->master[1] = WM_VOL_MUTE; | 2157 | spec->master[1] = WM_VOL_MUTE; |
@@ -2126,6 +2160,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2126 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); | 2160 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); |
2127 | } | 2161 | } |
2128 | 2162 | ||
2163 | #ifdef CONFIG_PM | ||
2164 | ice->pm_resume = aureon_resume; | ||
2165 | ice->pm_suspend_enabled = 1; | ||
2166 | #endif | ||
2167 | |||
2129 | return 0; | 2168 | return 0; |
2130 | } | 2169 | } |
2131 | 2170 | ||
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index b56e3367678..3c40d726b46 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/vmalloc.h> | 41 | #include <linux/vmalloc.h> |
42 | #include <linux/moduleparam.h> | 42 | #include <linux/moduleparam.h> |
43 | #include <linux/firmware.h> | 43 | #include <linux/firmware.h> |
44 | #include <linux/input.h> | ||
44 | #include <sound/core.h> | 45 | #include <sound/core.h> |
45 | #include <sound/info.h> | 46 | #include <sound/info.h> |
46 | #include <sound/control.h> | 47 | #include <sound/control.h> |
@@ -844,11 +845,17 @@ struct snd_m3 { | |||
844 | struct m3_dma *substreams; | 845 | struct m3_dma *substreams; |
845 | 846 | ||
846 | spinlock_t reg_lock; | 847 | spinlock_t reg_lock; |
847 | spinlock_t ac97_lock; | ||
848 | 848 | ||
849 | #ifdef CONFIG_SND_MAESTRO3_INPUT | ||
850 | struct input_dev *input_dev; | ||
851 | char phys[64]; /* physical device path */ | ||
852 | #else | ||
853 | spinlock_t ac97_lock; | ||
849 | struct snd_kcontrol *master_switch; | 854 | struct snd_kcontrol *master_switch; |
850 | struct snd_kcontrol *master_volume; | 855 | struct snd_kcontrol *master_volume; |
851 | struct tasklet_struct hwvol_tq; | 856 | struct tasklet_struct hwvol_tq; |
857 | #endif | ||
858 | |||
852 | unsigned int in_suspend; | 859 | unsigned int in_suspend; |
853 | 860 | ||
854 | #ifdef CONFIG_PM | 861 | #ifdef CONFIG_PM |
@@ -1598,18 +1605,32 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s) | |||
1598 | } | 1605 | } |
1599 | } | 1606 | } |
1600 | 1607 | ||
1608 | /* The m3's hardware volume works by incrementing / decrementing 2 counters | ||
1609 | (without wrap around) in response to volume button presses and then | ||
1610 | generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 | ||
1611 | of a byte wide register. The meaning of bits 0 and 4 is unknown. */ | ||
1601 | static void snd_m3_update_hw_volume(unsigned long private_data) | 1612 | static void snd_m3_update_hw_volume(unsigned long private_data) |
1602 | { | 1613 | { |
1603 | struct snd_m3 *chip = (struct snd_m3 *) private_data; | 1614 | struct snd_m3 *chip = (struct snd_m3 *) private_data; |
1604 | int x, val; | 1615 | int x, val; |
1616 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1605 | unsigned long flags; | 1617 | unsigned long flags; |
1618 | #endif | ||
1606 | 1619 | ||
1607 | /* Figure out which volume control button was pushed, | 1620 | /* Figure out which volume control button was pushed, |
1608 | based on differences from the default register | 1621 | based on differences from the default register |
1609 | values. */ | 1622 | values. */ |
1610 | x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; | 1623 | x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; |
1611 | 1624 | ||
1612 | /* Reset the volume control registers. */ | 1625 | /* Reset the volume counters to 4. Tests on the allegro integrated |
1626 | into a Compaq N600C laptop, have revealed that: | ||
1627 | 1) Writing any value will result in the 2 counters being reset to | ||
1628 | 4 so writing 0x88 is not strictly necessary | ||
1629 | 2) Writing to any of the 4 involved registers will reset all 4 | ||
1630 | of them (and reading them always returns the same value for all | ||
1631 | of them) | ||
1632 | It could be that a maestro deviates from this, so leave the code | ||
1633 | as is. */ | ||
1613 | outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); | 1634 | outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); |
1614 | outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); | 1635 | outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); |
1615 | outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); | 1636 | outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); |
@@ -1620,6 +1641,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data) | |||
1620 | if (chip->in_suspend) | 1641 | if (chip->in_suspend) |
1621 | return; | 1642 | return; |
1622 | 1643 | ||
1644 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1623 | if (!chip->master_switch || !chip->master_volume) | 1645 | if (!chip->master_switch || !chip->master_volume) |
1624 | return; | 1646 | return; |
1625 | 1647 | ||
@@ -1629,7 +1651,9 @@ static void snd_m3_update_hw_volume(unsigned long private_data) | |||
1629 | val = chip->ac97->regs[AC97_MASTER_VOL]; | 1651 | val = chip->ac97->regs[AC97_MASTER_VOL]; |
1630 | switch (x) { | 1652 | switch (x) { |
1631 | case 0x88: | 1653 | case 0x88: |
1632 | /* mute */ | 1654 | /* The counters have not changed, yet we've received a HV |
1655 | interrupt. According to tests run by various people this | ||
1656 | happens when pressing the mute button. */ | ||
1633 | val ^= 0x8000; | 1657 | val ^= 0x8000; |
1634 | chip->ac97->regs[AC97_MASTER_VOL] = val; | 1658 | chip->ac97->regs[AC97_MASTER_VOL] = val; |
1635 | outw(val, chip->iobase + CODEC_DATA); | 1659 | outw(val, chip->iobase + CODEC_DATA); |
@@ -1638,7 +1662,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data) | |||
1638 | &chip->master_switch->id); | 1662 | &chip->master_switch->id); |
1639 | break; | 1663 | break; |
1640 | case 0xaa: | 1664 | case 0xaa: |
1641 | /* volume up */ | 1665 | /* counters increased by 1 -> volume up */ |
1642 | if ((val & 0x7f) > 0) | 1666 | if ((val & 0x7f) > 0) |
1643 | val--; | 1667 | val--; |
1644 | if ((val & 0x7f00) > 0) | 1668 | if ((val & 0x7f00) > 0) |
@@ -1650,7 +1674,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data) | |||
1650 | &chip->master_volume->id); | 1674 | &chip->master_volume->id); |
1651 | break; | 1675 | break; |
1652 | case 0x66: | 1676 | case 0x66: |
1653 | /* volume down */ | 1677 | /* counters decreased by 1 -> volume down */ |
1654 | if ((val & 0x7f) < 0x1f) | 1678 | if ((val & 0x7f) < 0x1f) |
1655 | val++; | 1679 | val++; |
1656 | if ((val & 0x7f00) < 0x1f00) | 1680 | if ((val & 0x7f00) < 0x1f00) |
@@ -1663,6 +1687,35 @@ static void snd_m3_update_hw_volume(unsigned long private_data) | |||
1663 | break; | 1687 | break; |
1664 | } | 1688 | } |
1665 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 1689 | spin_unlock_irqrestore(&chip->ac97_lock, flags); |
1690 | #else | ||
1691 | if (!chip->input_dev) | ||
1692 | return; | ||
1693 | |||
1694 | val = 0; | ||
1695 | switch (x) { | ||
1696 | case 0x88: | ||
1697 | /* The counters have not changed, yet we've received a HV | ||
1698 | interrupt. According to tests run by various people this | ||
1699 | happens when pressing the mute button. */ | ||
1700 | val = KEY_MUTE; | ||
1701 | break; | ||
1702 | case 0xaa: | ||
1703 | /* counters increased by 1 -> volume up */ | ||
1704 | val = KEY_VOLUMEUP; | ||
1705 | break; | ||
1706 | case 0x66: | ||
1707 | /* counters decreased by 1 -> volume down */ | ||
1708 | val = KEY_VOLUMEDOWN; | ||
1709 | break; | ||
1710 | } | ||
1711 | |||
1712 | if (val) { | ||
1713 | input_report_key(chip->input_dev, val, 1); | ||
1714 | input_sync(chip->input_dev); | ||
1715 | input_report_key(chip->input_dev, val, 0); | ||
1716 | input_sync(chip->input_dev); | ||
1717 | } | ||
1718 | #endif | ||
1666 | } | 1719 | } |
1667 | 1720 | ||
1668 | static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) | 1721 | static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) |
@@ -1677,7 +1730,11 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) | |||
1677 | return IRQ_NONE; | 1730 | return IRQ_NONE; |
1678 | 1731 | ||
1679 | if (status & HV_INT_PENDING) | 1732 | if (status & HV_INT_PENDING) |
1733 | #ifdef CONFIG_SND_MAESTRO3_INPUT | ||
1734 | snd_m3_update_hw_volume((unsigned long)chip); | ||
1735 | #else | ||
1680 | tasklet_schedule(&chip->hwvol_tq); | 1736 | tasklet_schedule(&chip->hwvol_tq); |
1737 | #endif | ||
1681 | 1738 | ||
1682 | /* | 1739 | /* |
1683 | * ack an assp int if its running | 1740 | * ack an assp int if its running |
@@ -1943,18 +2000,24 @@ static unsigned short | |||
1943 | snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | 2000 | snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
1944 | { | 2001 | { |
1945 | struct snd_m3 *chip = ac97->private_data; | 2002 | struct snd_m3 *chip = ac97->private_data; |
2003 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1946 | unsigned long flags; | 2004 | unsigned long flags; |
2005 | #endif | ||
1947 | unsigned short data = 0xffff; | 2006 | unsigned short data = 0xffff; |
1948 | 2007 | ||
1949 | if (snd_m3_ac97_wait(chip)) | 2008 | if (snd_m3_ac97_wait(chip)) |
1950 | goto fail; | 2009 | goto fail; |
2010 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1951 | spin_lock_irqsave(&chip->ac97_lock, flags); | 2011 | spin_lock_irqsave(&chip->ac97_lock, flags); |
2012 | #endif | ||
1952 | snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); | 2013 | snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); |
1953 | if (snd_m3_ac97_wait(chip)) | 2014 | if (snd_m3_ac97_wait(chip)) |
1954 | goto fail_unlock; | 2015 | goto fail_unlock; |
1955 | data = snd_m3_inw(chip, CODEC_DATA); | 2016 | data = snd_m3_inw(chip, CODEC_DATA); |
1956 | fail_unlock: | 2017 | fail_unlock: |
2018 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1957 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 2019 | spin_unlock_irqrestore(&chip->ac97_lock, flags); |
2020 | #endif | ||
1958 | fail: | 2021 | fail: |
1959 | return data; | 2022 | return data; |
1960 | } | 2023 | } |
@@ -1963,14 +2026,20 @@ static void | |||
1963 | snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) | 2026 | snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) |
1964 | { | 2027 | { |
1965 | struct snd_m3 *chip = ac97->private_data; | 2028 | struct snd_m3 *chip = ac97->private_data; |
2029 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1966 | unsigned long flags; | 2030 | unsigned long flags; |
2031 | #endif | ||
1967 | 2032 | ||
1968 | if (snd_m3_ac97_wait(chip)) | 2033 | if (snd_m3_ac97_wait(chip)) |
1969 | return; | 2034 | return; |
2035 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1970 | spin_lock_irqsave(&chip->ac97_lock, flags); | 2036 | spin_lock_irqsave(&chip->ac97_lock, flags); |
2037 | #endif | ||
1971 | snd_m3_outw(chip, val, CODEC_DATA); | 2038 | snd_m3_outw(chip, val, CODEC_DATA); |
1972 | snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); | 2039 | snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); |
2040 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1973 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 2041 | spin_unlock_irqrestore(&chip->ac97_lock, flags); |
2042 | #endif | ||
1974 | } | 2043 | } |
1975 | 2044 | ||
1976 | 2045 | ||
@@ -2077,7 +2146,9 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip) | |||
2077 | { | 2146 | { |
2078 | struct snd_ac97_bus *pbus; | 2147 | struct snd_ac97_bus *pbus; |
2079 | struct snd_ac97_template ac97; | 2148 | struct snd_ac97_template ac97; |
2149 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2080 | struct snd_ctl_elem_id elem_id; | 2150 | struct snd_ctl_elem_id elem_id; |
2151 | #endif | ||
2081 | int err; | 2152 | int err; |
2082 | static struct snd_ac97_bus_ops ops = { | 2153 | static struct snd_ac97_bus_ops ops = { |
2083 | .write = snd_m3_ac97_write, | 2154 | .write = snd_m3_ac97_write, |
@@ -2097,6 +2168,7 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip) | |||
2097 | schedule_timeout_uninterruptible(msecs_to_jiffies(100)); | 2168 | schedule_timeout_uninterruptible(msecs_to_jiffies(100)); |
2098 | snd_ac97_write(chip->ac97, AC97_PCM, 0); | 2169 | snd_ac97_write(chip->ac97, AC97_PCM, 0); |
2099 | 2170 | ||
2171 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2100 | memset(&elem_id, 0, sizeof(elem_id)); | 2172 | memset(&elem_id, 0, sizeof(elem_id)); |
2101 | elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 2173 | elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
2102 | strcpy(elem_id.name, "Master Playback Switch"); | 2174 | strcpy(elem_id.name, "Master Playback Switch"); |
@@ -2105,6 +2177,7 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip) | |||
2105 | elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 2177 | elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
2106 | strcpy(elem_id.name, "Master Playback Volume"); | 2178 | strcpy(elem_id.name, "Master Playback Volume"); |
2107 | chip->master_volume = snd_ctl_find_id(chip->card, &elem_id); | 2179 | chip->master_volume = snd_ctl_find_id(chip->card, &elem_id); |
2180 | #endif | ||
2108 | 2181 | ||
2109 | return 0; | 2182 | return 0; |
2110 | } | 2183 | } |
@@ -2370,6 +2443,7 @@ snd_m3_enable_ints(struct snd_m3 *chip) | |||
2370 | val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/; | 2443 | val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/; |
2371 | if (chip->hv_config & HV_CTRL_ENABLE) | 2444 | if (chip->hv_config & HV_CTRL_ENABLE) |
2372 | val |= HV_INT_ENABLE; | 2445 | val |= HV_INT_ENABLE; |
2446 | outb(val, chip->iobase + HOST_INT_STATUS); | ||
2373 | outw(val, io + HOST_INT_CTRL); | 2447 | outw(val, io + HOST_INT_CTRL); |
2374 | outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, | 2448 | outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, |
2375 | io + ASSP_CONTROL_C); | 2449 | io + ASSP_CONTROL_C); |
@@ -2384,6 +2458,11 @@ static int snd_m3_free(struct snd_m3 *chip) | |||
2384 | struct m3_dma *s; | 2458 | struct m3_dma *s; |
2385 | int i; | 2459 | int i; |
2386 | 2460 | ||
2461 | #ifdef CONFIG_SND_MAESTRO3_INPUT | ||
2462 | if (chip->input_dev) | ||
2463 | input_unregister_device(chip->input_dev); | ||
2464 | #endif | ||
2465 | |||
2387 | if (chip->substreams) { | 2466 | if (chip->substreams) { |
2388 | spin_lock_irq(&chip->reg_lock); | 2467 | spin_lock_irq(&chip->reg_lock); |
2389 | for (i = 0; i < chip->num_substreams; i++) { | 2468 | for (i = 0; i < chip->num_substreams; i++) { |
@@ -2510,6 +2589,41 @@ static int m3_resume(struct pci_dev *pci) | |||
2510 | } | 2589 | } |
2511 | #endif /* CONFIG_PM */ | 2590 | #endif /* CONFIG_PM */ |
2512 | 2591 | ||
2592 | #ifdef CONFIG_SND_MAESTRO3_INPUT | ||
2593 | static int __devinit snd_m3_input_register(struct snd_m3 *chip) | ||
2594 | { | ||
2595 | struct input_dev *input_dev; | ||
2596 | int err; | ||
2597 | |||
2598 | input_dev = input_allocate_device(); | ||
2599 | if (!input_dev) | ||
2600 | return -ENOMEM; | ||
2601 | |||
2602 | snprintf(chip->phys, sizeof(chip->phys), "pci-%s/input0", | ||
2603 | pci_name(chip->pci)); | ||
2604 | |||
2605 | input_dev->name = chip->card->driver; | ||
2606 | input_dev->phys = chip->phys; | ||
2607 | input_dev->id.bustype = BUS_PCI; | ||
2608 | input_dev->id.vendor = chip->pci->vendor; | ||
2609 | input_dev->id.product = chip->pci->device; | ||
2610 | input_dev->dev.parent = &chip->pci->dev; | ||
2611 | |||
2612 | __set_bit(EV_KEY, input_dev->evbit); | ||
2613 | __set_bit(KEY_MUTE, input_dev->keybit); | ||
2614 | __set_bit(KEY_VOLUMEDOWN, input_dev->keybit); | ||
2615 | __set_bit(KEY_VOLUMEUP, input_dev->keybit); | ||
2616 | |||
2617 | err = input_register_device(input_dev); | ||
2618 | if (err) { | ||
2619 | input_free_device(input_dev); | ||
2620 | return err; | ||
2621 | } | ||
2622 | |||
2623 | chip->input_dev = input_dev; | ||
2624 | return 0; | ||
2625 | } | ||
2626 | #endif /* CONFIG_INPUT */ | ||
2513 | 2627 | ||
2514 | /* | 2628 | /* |
2515 | */ | 2629 | */ |
@@ -2553,7 +2667,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2553 | } | 2667 | } |
2554 | 2668 | ||
2555 | spin_lock_init(&chip->reg_lock); | 2669 | spin_lock_init(&chip->reg_lock); |
2670 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2556 | spin_lock_init(&chip->ac97_lock); | 2671 | spin_lock_init(&chip->ac97_lock); |
2672 | #endif | ||
2557 | 2673 | ||
2558 | switch (pci->device) { | 2674 | switch (pci->device) { |
2559 | case PCI_DEVICE_ID_ESS_ALLEGRO: | 2675 | case PCI_DEVICE_ID_ESS_ALLEGRO: |
@@ -2636,7 +2752,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2636 | 2752 | ||
2637 | snd_m3_hv_init(chip); | 2753 | snd_m3_hv_init(chip); |
2638 | 2754 | ||
2755 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2639 | tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); | 2756 | tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); |
2757 | #endif | ||
2640 | 2758 | ||
2641 | if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, | 2759 | if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, |
2642 | card->driver, chip)) { | 2760 | card->driver, chip)) { |
@@ -2668,7 +2786,16 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2668 | 2786 | ||
2669 | if ((err = snd_m3_pcm(chip, 0)) < 0) | 2787 | if ((err = snd_m3_pcm(chip, 0)) < 0) |
2670 | return err; | 2788 | return err; |
2671 | 2789 | ||
2790 | #ifdef CONFIG_SND_MAESTRO3_INPUT | ||
2791 | if (chip->hv_config & HV_CTRL_ENABLE) { | ||
2792 | err = snd_m3_input_register(chip); | ||
2793 | if (err) | ||
2794 | snd_printk(KERN_WARNING "Input device registration " | ||
2795 | "failed with error %i", err); | ||
2796 | } | ||
2797 | #endif | ||
2798 | |||
2672 | snd_m3_enable_ints(chip); | 2799 | snd_m3_enable_ints(chip); |
2673 | snd_m3_assp_continue(chip); | 2800 | snd_m3_assp_continue(chip); |
2674 | 2801 | ||
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 3be8f97c8bc..6c3fd4d1c49 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
@@ -1102,73 +1102,17 @@ static int snd_mixart_free(struct mixart_mgr *mgr) | |||
1102 | /* | 1102 | /* |
1103 | * proc interface | 1103 | * proc interface |
1104 | */ | 1104 | */ |
1105 | static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry, | ||
1106 | void *private_file_data, | ||
1107 | struct file *file, | ||
1108 | long long offset, | ||
1109 | int orig) | ||
1110 | { | ||
1111 | offset = offset & ~3; /* 4 bytes aligned */ | ||
1112 | |||
1113 | switch(orig) { | ||
1114 | case SEEK_SET: | ||
1115 | file->f_pos = offset; | ||
1116 | break; | ||
1117 | case SEEK_CUR: | ||
1118 | file->f_pos += offset; | ||
1119 | break; | ||
1120 | case SEEK_END: /* offset is negative */ | ||
1121 | file->f_pos = MIXART_BA0_SIZE + offset; | ||
1122 | break; | ||
1123 | default: | ||
1124 | return -EINVAL; | ||
1125 | } | ||
1126 | if(file->f_pos > MIXART_BA0_SIZE) | ||
1127 | file->f_pos = MIXART_BA0_SIZE; | ||
1128 | return file->f_pos; | ||
1129 | } | ||
1130 | |||
1131 | static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry, | ||
1132 | void *private_file_data, | ||
1133 | struct file *file, | ||
1134 | long long offset, | ||
1135 | int orig) | ||
1136 | { | ||
1137 | offset = offset & ~3; /* 4 bytes aligned */ | ||
1138 | |||
1139 | switch(orig) { | ||
1140 | case SEEK_SET: | ||
1141 | file->f_pos = offset; | ||
1142 | break; | ||
1143 | case SEEK_CUR: | ||
1144 | file->f_pos += offset; | ||
1145 | break; | ||
1146 | case SEEK_END: /* offset is negative */ | ||
1147 | file->f_pos = MIXART_BA1_SIZE + offset; | ||
1148 | break; | ||
1149 | default: | ||
1150 | return -EINVAL; | ||
1151 | } | ||
1152 | if(file->f_pos > MIXART_BA1_SIZE) | ||
1153 | file->f_pos = MIXART_BA1_SIZE; | ||
1154 | return file->f_pos; | ||
1155 | } | ||
1156 | 1105 | ||
1157 | /* | 1106 | /* |
1158 | mixart_BA0 proc interface for BAR 0 - read callback | 1107 | mixart_BA0 proc interface for BAR 0 - read callback |
1159 | */ | 1108 | */ |
1160 | static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private_data, | 1109 | static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry, |
1161 | struct file *file, char __user *buf, | 1110 | void *file_private_data, |
1162 | unsigned long count, unsigned long pos) | 1111 | struct file *file, char __user *buf, |
1112 | size_t count, loff_t pos) | ||
1163 | { | 1113 | { |
1164 | struct mixart_mgr *mgr = entry->private_data; | 1114 | struct mixart_mgr *mgr = entry->private_data; |
1165 | unsigned long maxsize; | ||
1166 | 1115 | ||
1167 | if (pos >= MIXART_BA0_SIZE) | ||
1168 | return 0; | ||
1169 | maxsize = MIXART_BA0_SIZE - pos; | ||
1170 | if (count > maxsize) | ||
1171 | count = maxsize; | ||
1172 | count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ | 1116 | count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ |
1173 | if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) | 1117 | if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) |
1174 | return -EFAULT; | 1118 | return -EFAULT; |
@@ -1178,18 +1122,13 @@ static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private | |||
1178 | /* | 1122 | /* |
1179 | mixart_BA1 proc interface for BAR 1 - read callback | 1123 | mixart_BA1 proc interface for BAR 1 - read callback |
1180 | */ | 1124 | */ |
1181 | static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private_data, | 1125 | static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry, |
1182 | struct file *file, char __user *buf, | 1126 | void *file_private_data, |
1183 | unsigned long count, unsigned long pos) | 1127 | struct file *file, char __user *buf, |
1128 | size_t count, loff_t pos) | ||
1184 | { | 1129 | { |
1185 | struct mixart_mgr *mgr = entry->private_data; | 1130 | struct mixart_mgr *mgr = entry->private_data; |
1186 | unsigned long maxsize; | ||
1187 | 1131 | ||
1188 | if (pos > MIXART_BA1_SIZE) | ||
1189 | return 0; | ||
1190 | maxsize = MIXART_BA1_SIZE - pos; | ||
1191 | if (count > maxsize) | ||
1192 | count = maxsize; | ||
1193 | count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ | 1132 | count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ |
1194 | if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) | 1133 | if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) |
1195 | return -EFAULT; | 1134 | return -EFAULT; |
@@ -1198,12 +1137,10 @@ static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private | |||
1198 | 1137 | ||
1199 | static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = { | 1138 | static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = { |
1200 | .read = snd_mixart_BA0_read, | 1139 | .read = snd_mixart_BA0_read, |
1201 | .llseek = snd_mixart_BA0_llseek | ||
1202 | }; | 1140 | }; |
1203 | 1141 | ||
1204 | static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = { | 1142 | static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = { |
1205 | .read = snd_mixart_BA1_read, | 1143 | .read = snd_mixart_BA1_read, |
1206 | .llseek = snd_mixart_BA1_llseek | ||
1207 | }; | 1144 | }; |
1208 | 1145 | ||
1209 | 1146 | ||