blob: 22606e3b08f4a9de15c561cda0a0a8a7fd99e24a [file] [log] [blame]
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001/*
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 */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +130024
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020025/* >0: print Hw params, timer vars. >1: print stream write/copy sizes */
26#define REALLY_VERBOSE_LOGGING 0
27
28#if REALLY_VERBOSE_LOGGING
29#define VPRINTK1 snd_printd
30#else
31#define VPRINTK1(...)
32#endif
33
34#if REALLY_VERBOSE_LOGGING > 1
35#define VPRINTK2 snd_printd
36#else
37#define VPRINTK2(...)
38#endif
39
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020040#include "hpi_internal.h"
41#include "hpimsginit.h"
42#include "hpioctl.h"
43
44#include <linux/pci.h>
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +130045#include <linux/version.h>
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020046#include <linux/init.h>
47#include <linux/jiffies.h>
48#include <linux/slab.h>
49#include <linux/time.h>
50#include <linux/wait.h>
51#include <sound/core.h>
52#include <sound/control.h>
53#include <sound/pcm.h>
54#include <sound/pcm_params.h>
55#include <sound/info.h>
56#include <sound/initval.h>
57#include <sound/tlv.h>
58#include <sound/hwdep.h>
59
60
61MODULE_LICENSE("GPL");
62MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
63MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
64
65static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */
66static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
67static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
68static int enable_hpi_hwdep = 1;
69
70module_param_array(index, int, NULL, S_IRUGO);
71MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard.");
72
73module_param_array(id, charp, NULL, S_IRUGO);
74MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard.");
75
76module_param_array(enable, bool, NULL, S_IRUGO);
77MODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard.");
78
79module_param(enable_hpi_hwdep, bool, S_IRUGO|S_IWUSR);
80MODULE_PARM_DESC(enable_hpi_hwdep,
81 "ALSA enable HPI hwdep for AudioScience soundcard ");
82
83/* identify driver */
84#ifdef KERNEL_ALSA_BUILD
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +130085static char *build_info = "Built using headers from kernel source";
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020086module_param(build_info, charp, S_IRUGO);
87MODULE_PARM_DESC(build_info, "built using headers from kernel source");
88#else
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +130089static char *build_info = "Built within ALSA source";
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020090module_param(build_info, charp, S_IRUGO);
91MODULE_PARM_DESC(build_info, "built within ALSA source");
92#endif
93
94/* set to 1 to dump every control from adapter to log */
95static const int mixer_dump;
96
97#define DEFAULT_SAMPLERATE 44100
98static int adapter_fs = DEFAULT_SAMPLERATE;
99
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200100/* defaults */
101#define PERIODS_MIN 2
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300102#define PERIOD_BYTES_MIN 2048
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200103#define BUFFER_BYTES_MAX (512 * 1024)
104
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300105/* convert stream to character */
106#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C')
107
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200108/*#define TIMER_MILLISECONDS 20
109#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000)
110*/
111
112#define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
113
114struct clk_source {
115 int source;
116 int index;
117 char *name;
118};
119
120struct clk_cache {
121 int count;
122 int has_local;
123 struct clk_source s[MAX_CLOCKSOURCES];
124};
125
126/* Per card data */
127struct snd_card_asihpi {
128 struct snd_card *card;
129 struct pci_dev *pci;
130 u16 adapter_index;
131 u32 serial_number;
132 u16 type;
133 u16 version;
134 u16 num_outstreams;
135 u16 num_instreams;
136
137 u32 h_mixer;
138 struct clk_cache cc;
139
140 u16 support_mmap;
141 u16 support_grouping;
142 u16 support_mrx;
143 u16 update_interval_frames;
144 u16 in_max_chans;
145 u16 out_max_chans;
146};
147
148/* Per stream data */
149struct snd_card_asihpi_pcm {
150 struct timer_list timer;
151 unsigned int respawn_timer;
152 unsigned int hpi_buffer_attached;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300153 unsigned int buffer_bytes;
154 unsigned int period_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200155 unsigned int bytes_per_sec;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300156 unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
157 unsigned int pcm_buf_dma_ofs; /* DMA R/W offset in buffer */
158 unsigned int pcm_buf_elapsed_dma_ofs; /* DMA R/W offset in buffer */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200159 struct snd_pcm_substream *substream;
160 u32 h_stream;
161 struct hpi_format format;
162};
163
164/* universal stream verbs work with out or in stream handles */
165
166/* Functions to allow driver to give a buffer to HPI for busmastering */
167
168static u16 hpi_stream_host_buffer_attach(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200169 u32 h_stream, /* handle to outstream. */
170 u32 size_in_bytes, /* size in bytes of bus mastering buffer */
171 u32 pci_address
172)
173{
174 struct hpi_message hm;
175 struct hpi_response hr;
176 unsigned int obj = hpi_handle_object(h_stream);
177
178 if (!h_stream)
179 return HPI_ERROR_INVALID_OBJ;
180 hpi_init_message_response(&hm, &hr, obj,
181 obj == HPI_OBJ_OSTREAM ?
182 HPI_OSTREAM_HOSTBUFFER_ALLOC :
183 HPI_ISTREAM_HOSTBUFFER_ALLOC);
184
185 hpi_handle_to_indexes(h_stream, &hm.adapter_index,
186 &hm.obj_index);
187
188 hm.u.d.u.buffer.buffer_size = size_in_bytes;
189 hm.u.d.u.buffer.pci_address = pci_address;
190 hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER;
191 hpi_send_recv(&hm, &hr);
192 return hr.error;
193}
194
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300195static u16 hpi_stream_host_buffer_detach(u32 h_stream)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200196{
197 struct hpi_message hm;
198 struct hpi_response hr;
199 unsigned int obj = hpi_handle_object(h_stream);
200
201 if (!h_stream)
202 return HPI_ERROR_INVALID_OBJ;
203
204 hpi_init_message_response(&hm, &hr, obj,
205 obj == HPI_OBJ_OSTREAM ?
206 HPI_OSTREAM_HOSTBUFFER_FREE :
207 HPI_ISTREAM_HOSTBUFFER_FREE);
208
209 hpi_handle_to_indexes(h_stream, &hm.adapter_index,
210 &hm.obj_index);
211 hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER;
212 hpi_send_recv(&hm, &hr);
213 return hr.error;
214}
215
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300216static inline u16 hpi_stream_start(u32 h_stream)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200217{
218 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300219 return hpi_outstream_start(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200220 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300221 return hpi_instream_start(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200222}
223
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300224static inline u16 hpi_stream_stop(u32 h_stream)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200225{
226 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300227 return hpi_outstream_stop(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200228 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300229 return hpi_instream_stop(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200230}
231
232static inline u16 hpi_stream_get_info_ex(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200233 u32 h_stream,
234 u16 *pw_state,
235 u32 *pbuffer_size,
236 u32 *pdata_in_buffer,
237 u32 *psample_count,
238 u32 *pauxiliary_data
239)
240{
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300241 u16 e;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200242 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300243 e = hpi_outstream_get_info_ex(h_stream, pw_state,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200244 pbuffer_size, pdata_in_buffer,
245 psample_count, pauxiliary_data);
246 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300247 e = hpi_instream_get_info_ex(h_stream, pw_state,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200248 pbuffer_size, pdata_in_buffer,
249 psample_count, pauxiliary_data);
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300250 return e;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200251}
252
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300253static inline u16 hpi_stream_group_add(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200254 u32 h_master,
255 u32 h_stream)
256{
257 if (hpi_handle_object(h_master) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300258 return hpi_outstream_group_add(h_master, h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200259 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300260 return hpi_instream_group_add(h_master, h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200261}
262
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300263static inline u16 hpi_stream_group_reset(u32 h_stream)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200264{
265 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300266 return hpi_outstream_group_reset(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200267 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300268 return hpi_instream_group_reset(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200269}
270
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300271static inline u16 hpi_stream_group_get_map(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200272 u32 h_stream, u32 *mo, u32 *mi)
273{
274 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300275 return hpi_outstream_group_get_map(h_stream, mo, mi);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200276 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300277 return hpi_instream_group_get_map(h_stream, mo, mi);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200278}
279
280static u16 handle_error(u16 err, int line, char *filename)
281{
282 if (err)
283 printk(KERN_WARNING
284 "in file %s, line %d: HPI error %d\n",
285 filename, line, err);
286 return err;
287}
288
289#define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__)
290
291/***************************** GENERAL PCM ****************/
292#if REALLY_VERBOSE_LOGGING
293static void print_hwparams(struct snd_pcm_hw_params *p)
294{
295 snd_printd("HWPARAMS \n");
296 snd_printd("samplerate %d \n", params_rate(p));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300297 snd_printd("Channels %d \n", params_channels(p));
298 snd_printd("Format %d \n", params_format(p));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200299 snd_printd("subformat %d \n", params_subformat(p));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300300 snd_printd("Buffer bytes %d \n", params_buffer_bytes(p));
301 snd_printd("Period bytes %d \n", params_period_bytes(p));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200302 snd_printd("access %d \n", params_access(p));
303 snd_printd("period_size %d \n", params_period_size(p));
304 snd_printd("periods %d \n", params_periods(p));
305 snd_printd("buffer_size %d \n", params_buffer_size(p));
306}
307#else
308#define print_hwparams(x)
309#endif
310
311static snd_pcm_format_t hpi_to_alsa_formats[] = {
312 -1, /* INVALID */
313 SNDRV_PCM_FORMAT_U8, /* HPI_FORMAT_PCM8_UNSIGNED 1 */
314 SNDRV_PCM_FORMAT_S16, /* HPI_FORMAT_PCM16_SIGNED 2 */
315 -1, /* HPI_FORMAT_MPEG_L1 3 */
316 SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L2 4 */
317 SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L3 5 */
318 -1, /* HPI_FORMAT_DOLBY_AC2 6 */
319 -1, /* HPI_FORMAT_DOLBY_AC3 7 */
320 SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN 8 */
321 -1, /* HPI_FORMAT_AA_TAGIT1_HITS 9 */
322 -1, /* HPI_FORMAT_AA_TAGIT1_INSERTS 10 */
323 SNDRV_PCM_FORMAT_S32, /* HPI_FORMAT_PCM32_SIGNED 11 */
324 -1, /* HPI_FORMAT_RAW_BITSTREAM 12 */
325 -1, /* HPI_FORMAT_AA_TAGIT1_HITS_EX1 13 */
326 SNDRV_PCM_FORMAT_FLOAT, /* HPI_FORMAT_PCM32_FLOAT 14 */
327#if 1
328 /* ALSA can't handle 3 byte sample size together with power-of-2
329 * constraint on buffer_bytes, so disable this format
330 */
331 -1
332#else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300333 /* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200334#endif
335};
336
337
338static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,
339 u16 *hpi_format)
340{
341 u16 format;
342
343 for (format = HPI_FORMAT_PCM8_UNSIGNED;
344 format <= HPI_FORMAT_PCM24_SIGNED; format++) {
345 if (hpi_to_alsa_formats[format] == alsa_format) {
346 *hpi_format = format;
347 return 0;
348 }
349 }
350
351 snd_printd(KERN_WARNING "failed match for alsa format %d\n",
352 alsa_format);
353 *hpi_format = 0;
354 return -EINVAL;
355}
356
357static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
358 struct snd_pcm_hardware *pcmhw)
359{
360 u16 err;
361 u32 h_control;
362 u32 sample_rate;
363 int idx;
364 unsigned int rate_min = 200000;
365 unsigned int rate_max = 0;
366 unsigned int rates = 0;
367
368 if (asihpi->support_mrx) {
369 rates |= SNDRV_PCM_RATE_CONTINUOUS;
370 rates |= SNDRV_PCM_RATE_8000_96000;
371 rate_min = 8000;
372 rate_max = 100000;
373 } else {
374 /* on cards without SRC,
375 valid rates are determined by sampleclock */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300376 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200377 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
378 HPI_CONTROL_SAMPLECLOCK, &h_control);
379 if (err) {
380 snd_printk(KERN_ERR
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300381 "No local sampleclock, err %d\n", err);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200382 }
383
Eliot Blennerhassett7bf76c32011-03-25 15:25:46 +1300384 for (idx = -1; idx < 100; idx++) {
385 if (idx == -1) {
386 if (hpi_sample_clock_get_sample_rate(h_control,
387 &sample_rate))
388 continue;
389 } else if (hpi_sample_clock_query_local_rate(h_control,
390 idx, &sample_rate)) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200391 break;
392 }
393
394 rate_min = min(rate_min, sample_rate);
395 rate_max = max(rate_max, sample_rate);
396
397 switch (sample_rate) {
398 case 5512:
399 rates |= SNDRV_PCM_RATE_5512;
400 break;
401 case 8000:
402 rates |= SNDRV_PCM_RATE_8000;
403 break;
404 case 11025:
405 rates |= SNDRV_PCM_RATE_11025;
406 break;
407 case 16000:
408 rates |= SNDRV_PCM_RATE_16000;
409 break;
410 case 22050:
411 rates |= SNDRV_PCM_RATE_22050;
412 break;
413 case 32000:
414 rates |= SNDRV_PCM_RATE_32000;
415 break;
416 case 44100:
417 rates |= SNDRV_PCM_RATE_44100;
418 break;
419 case 48000:
420 rates |= SNDRV_PCM_RATE_48000;
421 break;
422 case 64000:
423 rates |= SNDRV_PCM_RATE_64000;
424 break;
425 case 88200:
426 rates |= SNDRV_PCM_RATE_88200;
427 break;
428 case 96000:
429 rates |= SNDRV_PCM_RATE_96000;
430 break;
431 case 176400:
432 rates |= SNDRV_PCM_RATE_176400;
433 break;
434 case 192000:
435 rates |= SNDRV_PCM_RATE_192000;
436 break;
437 default: /* some other rate */
438 rates |= SNDRV_PCM_RATE_KNOT;
439 }
440 }
441 }
442
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200443 pcmhw->rates = rates;
444 pcmhw->rate_min = rate_min;
445 pcmhw->rate_max = rate_max;
446}
447
448static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
449 struct snd_pcm_hw_params *params)
450{
451 struct snd_pcm_runtime *runtime = substream->runtime;
452 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
453 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
454 int err;
455 u16 format;
Kulikov Vasiliy315e8f72010-07-15 22:48:19 +0400456 int width;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200457 unsigned int bytes_per_sec;
458
459 print_hwparams(params);
460 err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
461 if (err < 0)
462 return err;
463 err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format);
464 if (err)
465 return err;
466
467 VPRINTK1(KERN_INFO "format %d, %d chans, %d_hz\n",
468 format, params_channels(params),
469 params_rate(params));
470
471 hpi_handle_error(hpi_format_create(&dpcm->format,
472 params_channels(params),
473 format, params_rate(params), 0, 0));
474
475 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300476 if (hpi_instream_reset(dpcm->h_stream) != 0)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200477 return -EINVAL;
478
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300479 if (hpi_instream_set_format(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200480 dpcm->h_stream, &dpcm->format) != 0)
481 return -EINVAL;
482 }
483
484 dpcm->hpi_buffer_attached = 0;
485 if (card->support_mmap) {
486
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300487 err = hpi_stream_host_buffer_attach(dpcm->h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200488 params_buffer_bytes(params), runtime->dma_addr);
489 if (err == 0) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300490 VPRINTK1(KERN_INFO
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200491 "stream_host_buffer_attach succeeded %u %lu\n",
492 params_buffer_bytes(params),
493 (unsigned long)runtime->dma_addr);
494 } else {
495 snd_printd(KERN_INFO
496 "stream_host_buffer_attach error %d\n",
497 err);
498 return -ENOMEM;
499 }
500
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300501 err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200502 &dpcm->hpi_buffer_attached,
503 NULL, NULL, NULL);
504
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300505 VPRINTK1(KERN_INFO "stream_host_buffer_attach status 0x%x\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200506 dpcm->hpi_buffer_attached);
507 }
508 bytes_per_sec = params_rate(params) * params_channels(params);
Kulikov Vasiliy315e8f72010-07-15 22:48:19 +0400509 width = snd_pcm_format_width(params_format(params));
510 bytes_per_sec *= width;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200511 bytes_per_sec /= 8;
Kulikov Vasiliy315e8f72010-07-15 22:48:19 +0400512 if (width < 0 || bytes_per_sec == 0)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200513 return -EINVAL;
514
515 dpcm->bytes_per_sec = bytes_per_sec;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300516 dpcm->buffer_bytes = params_buffer_bytes(params);
517 dpcm->period_bytes = params_period_bytes(params);
518 VPRINTK1(KERN_INFO "buffer_bytes=%d, period_bytes=%d, bps=%d\n",
519 dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200520
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200521 return 0;
522}
523
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300524static int
525snd_card_asihpi_hw_free(struct snd_pcm_substream *substream)
526{
527 struct snd_pcm_runtime *runtime = substream->runtime;
528 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
529 if (dpcm->hpi_buffer_attached)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300530 hpi_stream_host_buffer_detach(dpcm->h_stream);
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300531
532 snd_pcm_lib_free_pages(substream);
533 return 0;
534}
535
536static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)
537{
538 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
539 kfree(dpcm);
540}
541
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200542static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
543 substream)
544{
545 struct snd_pcm_runtime *runtime = substream->runtime;
546 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
547 int expiry;
548
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300549 expiry = HZ / 200;
550 /*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300551 expiry = max(expiry, 1); /* don't let it be zero! */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200552 dpcm->timer.expires = jiffies + expiry;
553 dpcm->respawn_timer = 1;
554 add_timer(&dpcm->timer);
555}
556
557static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
558{
559 struct snd_pcm_runtime *runtime = substream->runtime;
560 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
561
562 dpcm->respawn_timer = 0;
563 del_timer(&dpcm->timer);
564}
565
566static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
567 int cmd)
568{
569 struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
570 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
571 struct snd_pcm_substream *s;
572 u16 e;
573
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300574 VPRINTK1(KERN_INFO "%c%d trigger\n",
575 SCHR(substream->stream), substream->number);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200576 switch (cmd) {
577 case SNDRV_PCM_TRIGGER_START:
578 snd_pcm_group_for_each_entry(s, substream) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300579 struct snd_pcm_runtime *runtime = s->runtime;
580 struct snd_card_asihpi_pcm *ds = runtime->private_data;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200581
582 if (snd_pcm_substream_chip(s) != card)
583 continue;
584
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300585 /* don't link Cap and Play */
586 if (substream->stream != s->stream)
587 continue;
588
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200589 if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
590 (card->support_mmap)) {
591 /* How do I know how much valid data is present
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300592 * in buffer? Must be at least one period!
593 * Guessing 2 periods, but if
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200594 * buffer is bigger it may contain even more
595 * data??
596 */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300597 unsigned int preload = ds->period_bytes * 1;
598 VPRINTK2(KERN_INFO "%d preload x%x\n", s->number, preload);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200599 hpi_handle_error(hpi_outstream_write_buf(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300600 ds->h_stream,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300601 &runtime->dma_area[0],
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200602 preload,
603 &ds->format));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300604 ds->pcm_buf_host_rw_ofs = preload;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200605 }
606
607 if (card->support_grouping) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300608 VPRINTK1(KERN_INFO "\t%c%d group\n",
609 SCHR(s->stream),
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200610 s->number);
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300611 e = hpi_stream_group_add(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200612 dpcm->h_stream,
613 ds->h_stream);
614 if (!e) {
615 snd_pcm_trigger_done(s, substream);
616 } else {
617 hpi_handle_error(e);
618 break;
619 }
620 } else
621 break;
622 }
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300623 VPRINTK1(KERN_INFO "start\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200624 /* start the master stream */
625 snd_card_asihpi_pcm_timer_start(substream);
Eliot Blennerhassettc4ed97d2011-02-10 17:26:20 +1300626 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
627 !card->support_mmap)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300628 hpi_handle_error(hpi_stream_start(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200629 break;
630
631 case SNDRV_PCM_TRIGGER_STOP:
632 snd_card_asihpi_pcm_timer_stop(substream);
633 snd_pcm_group_for_each_entry(s, substream) {
634 if (snd_pcm_substream_chip(s) != card)
635 continue;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300636 /* don't link Cap and Play */
637 if (substream->stream != s->stream)
638 continue;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200639
640 /*? workaround linked streams don't
641 transition to SETUP 20070706*/
642 s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
643
644 if (card->support_grouping) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300645 VPRINTK1(KERN_INFO "\t%c%d group\n",
646 SCHR(s->stream),
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200647 s->number);
648 snd_pcm_trigger_done(s, substream);
649 } else
650 break;
651 }
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300652 VPRINTK1(KERN_INFO "stop\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200653
654 /* _prepare and _hwparams reset the stream */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300655 hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200656 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
657 hpi_handle_error(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300658 hpi_outstream_reset(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200659
660 if (card->support_grouping)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300661 hpi_handle_error(hpi_stream_group_reset(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200662 break;
663
664 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300665 VPRINTK1(KERN_INFO "pause release\n");
666 hpi_handle_error(hpi_stream_start(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200667 snd_card_asihpi_pcm_timer_start(substream);
668 break;
669 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300670 VPRINTK1(KERN_INFO "pause\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200671 snd_card_asihpi_pcm_timer_stop(substream);
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300672 hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200673 break;
674 default:
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300675 snd_printd(KERN_ERR "\tINVALID\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200676 return -EINVAL;
677 }
678
679 return 0;
680}
681
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200682/*algorithm outline
683 Without linking degenerates to getting single stream pos etc
684 Without mmap 2nd loop degenerates to snd_pcm_period_elapsed
685*/
686/*
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300687pcm_buf_dma_ofs=get_buf_pos(s);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200688for_each_linked_stream(s) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300689 pcm_buf_dma_ofs=get_buf_pos(s);
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300690 min_buf_pos = modulo_min(min_buf_pos, pcm_buf_dma_ofs, buffer_bytes)
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300691 new_data = min(new_data, calc_new_data(pcm_buf_dma_ofs,irq_pos)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200692}
693timer.expires = jiffies + predict_next_period_ready(min_buf_pos);
694for_each_linked_stream(s) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300695 s->pcm_buf_dma_ofs = min_buf_pos;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300696 if (new_data > period_bytes) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200697 if (mmap) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300698 irq_pos = (irq_pos + period_bytes) % buffer_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200699 if (playback) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300700 write(period_bytes);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200701 } else {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300702 read(period_bytes);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200703 }
704 }
705 snd_pcm_period_elapsed(s);
706 }
707}
708*/
709
710/** Minimum of 2 modulo values. Works correctly when the difference between
711* the values is less than half the modulus
712*/
713static inline unsigned int modulo_min(unsigned int a, unsigned int b,
714 unsigned long int modulus)
715{
716 unsigned int result;
717 if (((a-b) % modulus) < (modulus/2))
718 result = b;
719 else
720 result = a;
721
722 return result;
723}
724
725/** Timer function, equivalent to interrupt service routine for cards
726*/
727static void snd_card_asihpi_timer_function(unsigned long data)
728{
729 struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300730 struct snd_pcm_substream *substream = dpcm->substream;
731 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200732 struct snd_pcm_runtime *runtime;
733 struct snd_pcm_substream *s;
734 unsigned int newdata = 0;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300735 unsigned int pcm_buf_dma_ofs, min_buf_pos = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200736 unsigned int remdata, xfercount, next_jiffies;
737 int first = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300738 int loops = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200739 u16 state;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300740 u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200741
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300742 VPRINTK1(KERN_INFO "%c%d snd_card_asihpi_timer_function\n",
743 SCHR(substream->stream), substream->number);
744
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200745 /* find minimum newdata and buffer pos in group */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300746 snd_pcm_group_for_each_entry(s, substream) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200747 struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
748 runtime = s->runtime;
749
750 if (snd_pcm_substream_chip(s) != card)
751 continue;
752
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300753 /* don't link Cap and Play */
754 if (substream->stream != s->stream)
755 continue;
756
757 hpi_handle_error(hpi_stream_get_info_ex(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200758 ds->h_stream, &state,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300759 &buffer_size, &bytes_avail,
760 &samples_played, &on_card_bytes));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200761
762 /* number of bytes in on-card buffer */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300763 runtime->delay = on_card_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200764
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300765 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300766 pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300767 if (state == HPI_STATE_STOPPED) {
768 if ((bytes_avail == 0) &&
769 (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
770 hpi_handle_error(hpi_stream_start(ds->h_stream));
771 VPRINTK1(KERN_INFO "P%d start\n", s->number);
772 }
773 } else if (state == HPI_STATE_DRAINED) {
774 VPRINTK1(KERN_WARNING "P%d drained\n",
775 s->number);
776 /*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
777 continue; */
778 }
779 } else
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300780 pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200781
782 if (first) {
783 /* can't statically init min when wrap is involved */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300784 min_buf_pos = pcm_buf_dma_ofs;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300785 newdata = (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200786 first = 0;
787 } else {
788 min_buf_pos =
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300789 modulo_min(min_buf_pos, pcm_buf_dma_ofs, UINT_MAX+1L);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200790 newdata = min(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300791 (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200792 newdata);
793 }
794
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300795 VPRINTK1(KERN_INFO "PB timer hw_ptr x%04lX, appl_ptr x%04lX\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200796 (unsigned long)frames_to_bytes(runtime,
797 runtime->status->hw_ptr),
798 (unsigned long)frames_to_bytes(runtime,
799 runtime->control->appl_ptr));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300800
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300801 VPRINTK1(KERN_INFO "%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X,"
802 " aux=x%04X space=x%04X\n",
803 loops, SCHR(s->stream), s->number,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300804 state, ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail,
805 (int)on_card_bytes, buffer_size-bytes_avail);
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300806 loops++;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200807 }
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300808 pcm_buf_dma_ofs = min_buf_pos;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200809
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300810 remdata = newdata % dpcm->period_bytes;
811 xfercount = newdata - remdata; /* a multiple of period_bytes */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300812 /* come back when on_card_bytes has decreased enough to allow
813 write to happen, or when data has been consumed to make another
814 period
815 */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300816 if (xfercount && (on_card_bytes > dpcm->period_bytes))
817 next_jiffies = ((on_card_bytes - dpcm->period_bytes) * HZ / dpcm->bytes_per_sec);
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300818 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300819 next_jiffies = ((dpcm->period_bytes - remdata) * HZ / dpcm->bytes_per_sec);
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300820
821 next_jiffies = max(next_jiffies, 1U);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200822 dpcm->timer.expires = jiffies + next_jiffies;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300823 VPRINTK1(KERN_INFO "jif %d buf pos x%04X newdata x%04X xfer x%04X\n",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300824 next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
825
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300826 snd_pcm_group_for_each_entry(s, substream) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200827 struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200828
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300829 /* don't link Cap and Play */
830 if (substream->stream != s->stream)
831 continue;
832
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300833 ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
834
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300835 if (xfercount && (on_card_bytes <= ds->period_bytes)) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200836 if (card->support_mmap) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200837 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300838 VPRINTK2(KERN_INFO "P%d write x%04x\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200839 s->number,
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300840 ds->period_bytes);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200841 hpi_handle_error(
842 hpi_outstream_write_buf(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300843 ds->h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200844 &s->runtime->
845 dma_area[0],
846 xfercount,
847 &ds->format));
848 } else {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300849 VPRINTK2(KERN_INFO "C%d read x%04x\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200850 s->number,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300851 xfercount);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200852 hpi_handle_error(
853 hpi_instream_read_buf(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300854 ds->h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200855 NULL, xfercount));
856 }
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300857 ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200858 } /* else R/W will be handled by read/write callbacks */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300859 ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200860 snd_pcm_period_elapsed(s);
861 }
862 }
863
864 if (dpcm->respawn_timer)
865 add_timer(&dpcm->timer);
866}
867
868/***************************** PLAYBACK OPS ****************/
869static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
870 unsigned int cmd, void *arg)
871{
872 /* snd_printd(KERN_INFO "Playback ioctl %d\n", cmd); */
873 return snd_pcm_lib_ioctl(substream, cmd, arg);
874}
875
876static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
877 substream)
878{
879 struct snd_pcm_runtime *runtime = substream->runtime;
880 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
881
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300882 VPRINTK1(KERN_INFO "playback prepare %d\n", substream->number);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200883
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300884 hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300885 dpcm->pcm_buf_host_rw_ofs = 0;
886 dpcm->pcm_buf_dma_ofs = 0;
887 dpcm->pcm_buf_elapsed_dma_ofs = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200888 return 0;
889}
890
891static snd_pcm_uframes_t
892snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
893{
894 struct snd_pcm_runtime *runtime = substream->runtime;
895 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
896 snd_pcm_uframes_t ptr;
897
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300898 ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
899 /* VPRINTK2(KERN_INFO "playback_pointer=x%04lx\n", (unsigned long)ptr); */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200900 return ptr;
901}
902
903static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
904 u32 h_stream,
905 struct snd_pcm_hardware *pcmhw)
906{
907 struct hpi_format hpi_format;
908 u16 format;
909 u16 err;
910 u32 h_control;
911 u32 sample_rate = 48000;
912
913 /* on cards without SRC, must query at valid rate,
914 * maybe set by external sync
915 */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300916 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200917 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
918 HPI_CONTROL_SAMPLECLOCK, &h_control);
919
920 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300921 err = hpi_sample_clock_get_sample_rate(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200922 &sample_rate);
923
924 for (format = HPI_FORMAT_PCM8_UNSIGNED;
925 format <= HPI_FORMAT_PCM24_SIGNED; format++) {
926 err = hpi_format_create(&hpi_format,
927 2, format, sample_rate, 128000, 0);
928 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300929 err = hpi_outstream_query_format(h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200930 &hpi_format);
931 if (!err && (hpi_to_alsa_formats[format] != -1))
932 pcmhw->formats |=
933 (1ULL << hpi_to_alsa_formats[format]);
934 }
935}
936
937static struct snd_pcm_hardware snd_card_asihpi_playback = {
938 .channels_min = 1,
939 .channels_max = 2,
940 .buffer_bytes_max = BUFFER_BYTES_MAX,
941 .period_bytes_min = PERIOD_BYTES_MIN,
942 .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
943 .periods_min = PERIODS_MIN,
944 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
945 .fifo_size = 0,
946};
947
948static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
949{
950 struct snd_pcm_runtime *runtime = substream->runtime;
951 struct snd_card_asihpi_pcm *dpcm;
952 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
953 int err;
954
955 dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
956 if (dpcm == NULL)
957 return -ENOMEM;
958
959 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300960 hpi_outstream_open(card->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200961 substream->number, &dpcm->h_stream);
962 hpi_handle_error(err);
963 if (err)
964 kfree(dpcm);
965 if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
966 return -EBUSY;
967 if (err)
968 return -EIO;
969
970 /*? also check ASI5000 samplerate source
971 If external, only support external rate.
972 If internal and other stream playing, cant switch
973 */
974
975 init_timer(&dpcm->timer);
976 dpcm->timer.data = (unsigned long) dpcm;
977 dpcm->timer.function = snd_card_asihpi_timer_function;
978 dpcm->substream = substream;
979 runtime->private_data = dpcm;
980 runtime->private_free = snd_card_asihpi_runtime_free;
981
982 snd_card_asihpi_playback.channels_max = card->out_max_chans;
983 /*?snd_card_asihpi_playback.period_bytes_min =
984 card->out_max_chans * 4096; */
985
986 snd_card_asihpi_playback_format(card, dpcm->h_stream,
987 &snd_card_asihpi_playback);
988
989 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_playback);
990
991 snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED |
992 SNDRV_PCM_INFO_DOUBLE |
993 SNDRV_PCM_INFO_BATCH |
994 SNDRV_PCM_INFO_BLOCK_TRANSFER |
995 SNDRV_PCM_INFO_PAUSE;
996
997 if (card->support_mmap)
998 snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP |
999 SNDRV_PCM_INFO_MMAP_VALID;
1000
1001 if (card->support_grouping)
1002 snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
1003
1004 /* struct is copied, so can create initializer dynamically */
1005 runtime->hw = snd_card_asihpi_playback;
1006
1007 if (card->support_mmap)
1008 err = snd_pcm_hw_constraint_pow2(runtime, 0,
1009 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1010 if (err < 0)
1011 return err;
1012
1013 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1014 card->update_interval_frames);
1015 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001016 card->update_interval_frames * 2, UINT_MAX);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001017
1018 snd_pcm_set_sync(substream);
1019
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001020 VPRINTK1(KERN_INFO "playback open\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001021
1022 return 0;
1023}
1024
1025static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
1026{
1027 struct snd_pcm_runtime *runtime = substream->runtime;
1028 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1029
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001030 hpi_handle_error(hpi_outstream_close(dpcm->h_stream));
1031 VPRINTK1(KERN_INFO "playback close\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001032
1033 return 0;
1034}
1035
1036static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
1037 int channel,
1038 snd_pcm_uframes_t pos,
1039 void __user *src,
1040 snd_pcm_uframes_t count)
1041{
1042 struct snd_pcm_runtime *runtime = substream->runtime;
1043 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1044 unsigned int len;
1045
1046 len = frames_to_bytes(runtime, count);
1047
1048 if (copy_from_user(runtime->dma_area, src, len))
1049 return -EFAULT;
1050
1051 VPRINTK2(KERN_DEBUG "playback copy%d %u bytes\n",
1052 substream->number, len);
1053
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001054 hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001055 runtime->dma_area, len, &dpcm->format));
1056
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001057 dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
1058
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001059 return 0;
1060}
1061
1062static int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
1063 substream, int channel,
1064 snd_pcm_uframes_t pos,
1065 snd_pcm_uframes_t count)
1066{
1067 unsigned int len;
1068 struct snd_pcm_runtime *runtime = substream->runtime;
1069 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1070
1071 len = frames_to_bytes(runtime, count);
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001072 VPRINTK1(KERN_INFO "playback silence %u bytes\n", len);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001073
1074 memset(runtime->dma_area, 0, len);
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001075 hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001076 runtime->dma_area, len, &dpcm->format));
1077 return 0;
1078}
1079
1080static struct snd_pcm_ops snd_card_asihpi_playback_ops = {
1081 .open = snd_card_asihpi_playback_open,
1082 .close = snd_card_asihpi_playback_close,
1083 .ioctl = snd_card_asihpi_playback_ioctl,
1084 .hw_params = snd_card_asihpi_pcm_hw_params,
1085 .hw_free = snd_card_asihpi_hw_free,
1086 .prepare = snd_card_asihpi_playback_prepare,
1087 .trigger = snd_card_asihpi_trigger,
1088 .pointer = snd_card_asihpi_playback_pointer,
1089 .copy = snd_card_asihpi_playback_copy,
1090 .silence = snd_card_asihpi_playback_silence,
1091};
1092
1093static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
1094 .open = snd_card_asihpi_playback_open,
1095 .close = snd_card_asihpi_playback_close,
1096 .ioctl = snd_card_asihpi_playback_ioctl,
1097 .hw_params = snd_card_asihpi_pcm_hw_params,
1098 .hw_free = snd_card_asihpi_hw_free,
1099 .prepare = snd_card_asihpi_playback_prepare,
1100 .trigger = snd_card_asihpi_trigger,
1101 .pointer = snd_card_asihpi_playback_pointer,
1102};
1103
1104/***************************** CAPTURE OPS ****************/
1105static snd_pcm_uframes_t
1106snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
1107{
1108 struct snd_pcm_runtime *runtime = substream->runtime;
1109 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1110
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001111 VPRINTK2(KERN_INFO "capture pointer %d=%d\n",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001112 substream->number, dpcm->pcm_buf_dma_ofs);
1113 /* NOTE Unlike playback can't use actual samples_played
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001114 for the capture position, because those samples aren't yet in
1115 the local buffer available for reading.
1116 */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001117 return bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001118}
1119
1120static int snd_card_asihpi_capture_ioctl(struct snd_pcm_substream *substream,
1121 unsigned int cmd, void *arg)
1122{
1123 return snd_pcm_lib_ioctl(substream, cmd, arg);
1124}
1125
1126static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
1127{
1128 struct snd_pcm_runtime *runtime = substream->runtime;
1129 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1130
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001131 hpi_handle_error(hpi_instream_reset(dpcm->h_stream));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001132 dpcm->pcm_buf_host_rw_ofs = 0;
1133 dpcm->pcm_buf_dma_ofs = 0;
1134 dpcm->pcm_buf_elapsed_dma_ofs = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001135
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001136 VPRINTK1("Capture Prepare %d\n", substream->number);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001137 return 0;
1138}
1139
1140
1141
1142static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
1143 u32 h_stream,
1144 struct snd_pcm_hardware *pcmhw)
1145{
1146 struct hpi_format hpi_format;
1147 u16 format;
1148 u16 err;
1149 u32 h_control;
1150 u32 sample_rate = 48000;
1151
1152 /* on cards without SRC, must query at valid rate,
1153 maybe set by external sync */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001154 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001155 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
1156 HPI_CONTROL_SAMPLECLOCK, &h_control);
1157
1158 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001159 err = hpi_sample_clock_get_sample_rate(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001160 &sample_rate);
1161
1162 for (format = HPI_FORMAT_PCM8_UNSIGNED;
1163 format <= HPI_FORMAT_PCM24_SIGNED; format++) {
1164
1165 err = hpi_format_create(&hpi_format, 2, format,
1166 sample_rate, 128000, 0);
1167 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001168 err = hpi_instream_query_format(h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001169 &hpi_format);
1170 if (!err)
1171 pcmhw->formats |=
1172 (1ULL << hpi_to_alsa_formats[format]);
1173 }
1174}
1175
1176
1177static struct snd_pcm_hardware snd_card_asihpi_capture = {
1178 .channels_min = 1,
1179 .channels_max = 2,
1180 .buffer_bytes_max = BUFFER_BYTES_MAX,
1181 .period_bytes_min = PERIOD_BYTES_MIN,
1182 .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
1183 .periods_min = PERIODS_MIN,
1184 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
1185 .fifo_size = 0,
1186};
1187
1188static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
1189{
1190 struct snd_pcm_runtime *runtime = substream->runtime;
1191 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
1192 struct snd_card_asihpi_pcm *dpcm;
1193 int err;
1194
1195 dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
1196 if (dpcm == NULL)
1197 return -ENOMEM;
1198
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001199 VPRINTK1("hpi_instream_open adapter %d stream %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001200 card->adapter_index, substream->number);
1201
1202 err = hpi_handle_error(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001203 hpi_instream_open(card->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001204 substream->number, &dpcm->h_stream));
1205 if (err)
1206 kfree(dpcm);
1207 if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
1208 return -EBUSY;
1209 if (err)
1210 return -EIO;
1211
1212
1213 init_timer(&dpcm->timer);
1214 dpcm->timer.data = (unsigned long) dpcm;
1215 dpcm->timer.function = snd_card_asihpi_timer_function;
1216 dpcm->substream = substream;
1217 runtime->private_data = dpcm;
1218 runtime->private_free = snd_card_asihpi_runtime_free;
1219
1220 snd_card_asihpi_capture.channels_max = card->in_max_chans;
1221 snd_card_asihpi_capture_format(card, dpcm->h_stream,
1222 &snd_card_asihpi_capture);
1223 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture);
1224 snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED;
1225
1226 if (card->support_mmap)
1227 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
1228 SNDRV_PCM_INFO_MMAP_VALID;
1229
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001230 if (card->support_grouping)
1231 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
1232
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001233 runtime->hw = snd_card_asihpi_capture;
1234
1235 if (card->support_mmap)
1236 err = snd_pcm_hw_constraint_pow2(runtime, 0,
1237 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1238 if (err < 0)
1239 return err;
1240
1241 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1242 card->update_interval_frames);
1243 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1244 card->update_interval_frames * 2, UINT_MAX);
1245
1246 snd_pcm_set_sync(substream);
1247
1248 return 0;
1249}
1250
1251static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
1252{
1253 struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
1254
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001255 hpi_handle_error(hpi_instream_close(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001256 return 0;
1257}
1258
1259static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
1260 int channel, snd_pcm_uframes_t pos,
1261 void __user *dst, snd_pcm_uframes_t count)
1262{
1263 struct snd_pcm_runtime *runtime = substream->runtime;
1264 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001265 u32 len;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001266
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001267 len = frames_to_bytes(runtime, count);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001268
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001269 VPRINTK2(KERN_INFO "capture copy%d %d bytes\n", substream->number, len);
1270 hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001271 runtime->dma_area, len));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001272
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001273 dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001274
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001275 if (copy_to_user(dst, runtime->dma_area, len))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001276 return -EFAULT;
1277
1278 return 0;
1279}
1280
1281static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
1282 .open = snd_card_asihpi_capture_open,
1283 .close = snd_card_asihpi_capture_close,
1284 .ioctl = snd_card_asihpi_capture_ioctl,
1285 .hw_params = snd_card_asihpi_pcm_hw_params,
1286 .hw_free = snd_card_asihpi_hw_free,
1287 .prepare = snd_card_asihpi_capture_prepare,
1288 .trigger = snd_card_asihpi_trigger,
1289 .pointer = snd_card_asihpi_capture_pointer,
1290};
1291
1292static struct snd_pcm_ops snd_card_asihpi_capture_ops = {
1293 .open = snd_card_asihpi_capture_open,
1294 .close = snd_card_asihpi_capture_close,
1295 .ioctl = snd_card_asihpi_capture_ioctl,
1296 .hw_params = snd_card_asihpi_pcm_hw_params,
1297 .hw_free = snd_card_asihpi_hw_free,
1298 .prepare = snd_card_asihpi_capture_prepare,
1299 .trigger = snd_card_asihpi_trigger,
1300 .pointer = snd_card_asihpi_capture_pointer,
1301 .copy = snd_card_asihpi_capture_copy
1302};
1303
1304static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
1305 int device, int substreams)
1306{
1307 struct snd_pcm *pcm;
1308 int err;
1309
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001310 err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001311 asihpi->num_outstreams, asihpi->num_instreams,
1312 &pcm);
1313 if (err < 0)
1314 return err;
1315 /* pointer to ops struct is stored, dont change ops afterwards! */
1316 if (asihpi->support_mmap) {
1317 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1318 &snd_card_asihpi_playback_mmap_ops);
1319 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1320 &snd_card_asihpi_capture_mmap_ops);
1321 } else {
1322 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1323 &snd_card_asihpi_playback_ops);
1324 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1325 &snd_card_asihpi_capture_ops);
1326 }
1327
1328 pcm->private_data = asihpi;
1329 pcm->info_flags = 0;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001330 strcpy(pcm->name, "Asihpi PCM");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001331
1332 /*? do we want to emulate MMAP for non-BBM cards?
1333 Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
1334 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1335 snd_dma_pci_data(asihpi->pci),
1336 64*1024, BUFFER_BYTES_MAX);
1337
1338 return 0;
1339}
1340
1341/***************************** MIXER CONTROLS ****************/
1342struct hpi_control {
1343 u32 h_control;
1344 u16 control_type;
1345 u16 src_node_type;
1346 u16 src_node_index;
1347 u16 dst_node_type;
1348 u16 dst_node_index;
1349 u16 band;
1350 char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
1351};
1352
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001353static const char * const asihpi_tuner_band_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001354 "invalid",
1355 "AM",
1356 "FM mono",
1357 "TV NTSC-M",
1358 "FM stereo",
1359 "AUX",
1360 "TV PAL BG",
1361 "TV PAL I",
1362 "TV PAL DK",
1363 "TV SECAM",
1364};
1365
1366compile_time_assert(
1367 (ARRAY_SIZE(asihpi_tuner_band_names) ==
1368 (HPI_TUNER_BAND_LAST+1)),
1369 assert_tuner_band_names_size);
1370
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001371static const char * const asihpi_src_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001372 "no source",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001373 "PCM",
1374 "Line",
1375 "Digital",
1376 "Tuner",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001377 "RF",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001378 "Clock",
1379 "Bitstream",
1380 "Microphone",
1381 "Cobranet",
1382 "Analog",
1383 "Adapter",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001384};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001385
1386compile_time_assert(
1387 (ARRAY_SIZE(asihpi_src_names) ==
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12001388 (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001389 assert_src_names_size);
1390
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001391static const char * const asihpi_dst_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001392 "no destination",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001393 "PCM",
1394 "Line",
1395 "Digital",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001396 "RF",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001397 "Speaker",
1398 "Cobranet Out",
1399 "Analog"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001400};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001401
1402compile_time_assert(
1403 (ARRAY_SIZE(asihpi_dst_names) ==
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12001404 (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001405 assert_dst_names_size);
1406
1407static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
1408 struct snd_card_asihpi *asihpi)
1409{
1410 int err;
1411
1412 err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi));
1413 if (err < 0)
1414 return err;
1415 else if (mixer_dump)
1416 snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index);
1417
1418 return 0;
1419}
1420
1421/* Convert HPI control name and location into ALSA control name */
1422static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
1423 struct hpi_control *hpi_ctl,
1424 char *name)
1425{
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001426 char *dir = "";
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001427 memset(snd_control, 0, sizeof(*snd_control));
1428 snd_control->name = hpi_ctl->name;
1429 snd_control->private_value = hpi_ctl->h_control;
1430 snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1431 snd_control->index = 0;
1432
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001433 if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
1434 dir = "Capture "; /* On or towards a PCM capture destination*/
1435 else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1436 (!hpi_ctl->dst_node_type))
1437 dir = "Capture "; /* On a source node that is not PCM playback */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001438 else if (hpi_ctl->src_node_type &&
1439 (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001440 (hpi_ctl->dst_node_type))
1441 dir = "Monitor Playback "; /* Between an input and an output */
1442 else
1443 dir = "Playback "; /* PCM Playback source, or output node */
1444
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001445 if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001446 sprintf(hpi_ctl->name, "%s%d %s%d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001447 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,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001451 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001452 else if (hpi_ctl->dst_node_type) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001453 sprintf(hpi_ctl->name, "%s %d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001454 asihpi_dst_names[hpi_ctl->dst_node_type],
1455 hpi_ctl->dst_node_index,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001456 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001457 } else {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001458 sprintf(hpi_ctl->name, "%s %d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001459 asihpi_src_names[hpi_ctl->src_node_type],
1460 hpi_ctl->src_node_index,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001461 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001462 }
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001463 /* printk(KERN_INFO "Adding %s %d to %d ", hpi_ctl->name,
1464 hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001465}
1466
1467/*------------------------------------------------------------
1468 Volume controls
1469 ------------------------------------------------------------*/
1470#define VOL_STEP_mB 1
1471static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
1472 struct snd_ctl_elem_info *uinfo)
1473{
1474 u32 h_control = kcontrol->private_value;
1475 u16 err;
1476 /* native gains are in millibels */
1477 short min_gain_mB;
1478 short max_gain_mB;
1479 short step_gain_mB;
1480
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001481 err = hpi_volume_query_range(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001482 &min_gain_mB, &max_gain_mB, &step_gain_mB);
1483 if (err) {
1484 max_gain_mB = 0;
1485 min_gain_mB = -10000;
1486 step_gain_mB = VOL_STEP_mB;
1487 }
1488
1489 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1490 uinfo->count = 2;
1491 uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;
1492 uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;
1493 uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;
1494 return 0;
1495}
1496
1497static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
1498 struct snd_ctl_elem_value *ucontrol)
1499{
1500 u32 h_control = kcontrol->private_value;
1501 short an_gain_mB[HPI_MAX_CHANNELS];
1502
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001503 hpi_handle_error(hpi_volume_get_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001504 ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;
1505 ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;
1506
1507 return 0;
1508}
1509
1510static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
1511 struct snd_ctl_elem_value *ucontrol)
1512{
1513 int change;
1514 u32 h_control = kcontrol->private_value;
1515 short an_gain_mB[HPI_MAX_CHANNELS];
1516
1517 an_gain_mB[0] =
1518 (ucontrol->value.integer.value[0]) * VOL_STEP_mB;
1519 an_gain_mB[1] =
1520 (ucontrol->value.integer.value[1]) * VOL_STEP_mB;
1521 /* change = asihpi->mixer_volume[addr][0] != left ||
1522 asihpi->mixer_volume[addr][1] != right;
1523 */
1524 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001525 hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001526 return change;
1527}
1528
1529static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
1530
1531static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
1532 struct hpi_control *hpi_ctl)
1533{
1534 struct snd_card *card = asihpi->card;
1535 struct snd_kcontrol_new snd_control;
1536
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001537 asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001538 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1539 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1540 snd_control.info = snd_asihpi_volume_info;
1541 snd_control.get = snd_asihpi_volume_get;
1542 snd_control.put = snd_asihpi_volume_put;
1543 snd_control.tlv.p = db_scale_100;
1544
1545 return ctl_add(card, &snd_control, asihpi);
1546}
1547
1548/*------------------------------------------------------------
1549 Level controls
1550 ------------------------------------------------------------*/
1551static int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,
1552 struct snd_ctl_elem_info *uinfo)
1553{
1554 u32 h_control = kcontrol->private_value;
1555 u16 err;
1556 short min_gain_mB;
1557 short max_gain_mB;
1558 short step_gain_mB;
1559
1560 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001561 hpi_level_query_range(h_control, &min_gain_mB,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001562 &max_gain_mB, &step_gain_mB);
1563 if (err) {
1564 max_gain_mB = 2400;
1565 min_gain_mB = -1000;
1566 step_gain_mB = 100;
1567 }
1568
1569 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1570 uinfo->count = 2;
1571 uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB;
1572 uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB;
1573 uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB;
1574 return 0;
1575}
1576
1577static int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,
1578 struct snd_ctl_elem_value *ucontrol)
1579{
1580 u32 h_control = kcontrol->private_value;
1581 short an_gain_mB[HPI_MAX_CHANNELS];
1582
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001583 hpi_handle_error(hpi_level_get_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001584 ucontrol->value.integer.value[0] =
1585 an_gain_mB[0] / HPI_UNITS_PER_dB;
1586 ucontrol->value.integer.value[1] =
1587 an_gain_mB[1] / HPI_UNITS_PER_dB;
1588
1589 return 0;
1590}
1591
1592static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,
1593 struct snd_ctl_elem_value *ucontrol)
1594{
1595 int change;
1596 u32 h_control = kcontrol->private_value;
1597 short an_gain_mB[HPI_MAX_CHANNELS];
1598
1599 an_gain_mB[0] =
1600 (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1601 an_gain_mB[1] =
1602 (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB;
1603 /* change = asihpi->mixer_level[addr][0] != left ||
1604 asihpi->mixer_level[addr][1] != right;
1605 */
1606 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001607 hpi_handle_error(hpi_level_set_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001608 return change;
1609}
1610
1611static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0);
1612
1613static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
1614 struct hpi_control *hpi_ctl)
1615{
1616 struct snd_card *card = asihpi->card;
1617 struct snd_kcontrol_new snd_control;
1618
1619 /* can't use 'volume' cos some nodes have volume as well */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001620 asihpi_ctl_init(&snd_control, hpi_ctl, "Level");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001621 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1622 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1623 snd_control.info = snd_asihpi_level_info;
1624 snd_control.get = snd_asihpi_level_get;
1625 snd_control.put = snd_asihpi_level_put;
1626 snd_control.tlv.p = db_scale_level;
1627
1628 return ctl_add(card, &snd_control, asihpi);
1629}
1630
1631/*------------------------------------------------------------
1632 AESEBU controls
1633 ------------------------------------------------------------*/
1634
1635/* AESEBU format */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001636static const char * const asihpi_aesebu_format_names[] = {
1637 "N/A", "S/PDIF", "AES/EBU" };
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001638
1639static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
1640 struct snd_ctl_elem_info *uinfo)
1641{
1642 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1643 uinfo->count = 1;
1644 uinfo->value.enumerated.items = 3;
1645
1646 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1647 uinfo->value.enumerated.item =
1648 uinfo->value.enumerated.items - 1;
1649
1650 strcpy(uinfo->value.enumerated.name,
1651 asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
1652
1653 return 0;
1654}
1655
1656static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
1657 struct snd_ctl_elem_value *ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001658 u16 (*func)(u32, u16 *))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001659{
1660 u32 h_control = kcontrol->private_value;
1661 u16 source, err;
1662
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001663 err = func(h_control, &source);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001664
1665 /* default to N/A */
1666 ucontrol->value.enumerated.item[0] = 0;
1667 /* return success but set the control to N/A */
1668 if (err)
1669 return 0;
1670 if (source == HPI_AESEBU_FORMAT_SPDIF)
1671 ucontrol->value.enumerated.item[0] = 1;
1672 if (source == HPI_AESEBU_FORMAT_AESEBU)
1673 ucontrol->value.enumerated.item[0] = 2;
1674
1675 return 0;
1676}
1677
1678static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
1679 struct snd_ctl_elem_value *ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001680 u16 (*func)(u32, u16))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001681{
1682 u32 h_control = kcontrol->private_value;
1683
1684 /* default to S/PDIF */
1685 u16 source = HPI_AESEBU_FORMAT_SPDIF;
1686
1687 if (ucontrol->value.enumerated.item[0] == 1)
1688 source = HPI_AESEBU_FORMAT_SPDIF;
1689 if (ucontrol->value.enumerated.item[0] == 2)
1690 source = HPI_AESEBU_FORMAT_AESEBU;
1691
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001692 if (func(h_control, source) != 0)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001693 return -EINVAL;
1694
1695 return 1;
1696}
1697
1698static int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,
1699 struct snd_ctl_elem_value *ucontrol) {
1700 return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001701 hpi_aesebu_receiver_get_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001702}
1703
1704static int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,
1705 struct snd_ctl_elem_value *ucontrol) {
1706 return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001707 hpi_aesebu_receiver_set_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001708}
1709
1710static int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol,
1711 struct snd_ctl_elem_info *uinfo)
1712{
1713 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1714 uinfo->count = 1;
1715
1716 uinfo->value.integer.min = 0;
1717 uinfo->value.integer.max = 0X1F;
1718 uinfo->value.integer.step = 1;
1719
1720 return 0;
1721}
1722
1723static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,
1724 struct snd_ctl_elem_value *ucontrol) {
1725
1726 u32 h_control = kcontrol->private_value;
1727 u16 status;
1728
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001729 hpi_handle_error(hpi_aesebu_receiver_get_error_status(
1730 h_control, &status));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001731 ucontrol->value.integer.value[0] = status;
1732 return 0;
1733}
1734
1735static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
1736 struct hpi_control *hpi_ctl)
1737{
1738 struct snd_card *card = asihpi->card;
1739 struct snd_kcontrol_new snd_control;
1740
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001741 asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001742 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1743 snd_control.info = snd_asihpi_aesebu_format_info;
1744 snd_control.get = snd_asihpi_aesebu_rx_format_get;
1745 snd_control.put = snd_asihpi_aesebu_rx_format_put;
1746
1747
1748 if (ctl_add(card, &snd_control, asihpi) < 0)
1749 return -EINVAL;
1750
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001751 asihpi_ctl_init(&snd_control, hpi_ctl, "Status");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001752 snd_control.access =
1753 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
1754 snd_control.info = snd_asihpi_aesebu_rxstatus_info;
1755 snd_control.get = snd_asihpi_aesebu_rxstatus_get;
1756
1757 return ctl_add(card, &snd_control, asihpi);
1758}
1759
1760static int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,
1761 struct snd_ctl_elem_value *ucontrol) {
1762 return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001763 hpi_aesebu_transmitter_get_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001764}
1765
1766static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,
1767 struct snd_ctl_elem_value *ucontrol) {
1768 return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001769 hpi_aesebu_transmitter_set_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001770}
1771
1772
1773static int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,
1774 struct hpi_control *hpi_ctl)
1775{
1776 struct snd_card *card = asihpi->card;
1777 struct snd_kcontrol_new snd_control;
1778
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001779 asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001780 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1781 snd_control.info = snd_asihpi_aesebu_format_info;
1782 snd_control.get = snd_asihpi_aesebu_tx_format_get;
1783 snd_control.put = snd_asihpi_aesebu_tx_format_put;
1784
1785 return ctl_add(card, &snd_control, asihpi);
1786}
1787
1788/*------------------------------------------------------------
1789 Tuner controls
1790 ------------------------------------------------------------*/
1791
1792/* Gain */
1793
1794static int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,
1795 struct snd_ctl_elem_info *uinfo)
1796{
1797 u32 h_control = kcontrol->private_value;
1798 u16 err;
1799 short idx;
1800 u16 gain_range[3];
1801
1802 for (idx = 0; idx < 3; idx++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001803 err = hpi_tuner_query_gain(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001804 idx, &gain_range[idx]);
1805 if (err != 0)
1806 return err;
1807 }
1808
1809 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1810 uinfo->count = 1;
1811 uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB;
1812 uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB;
1813 uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB;
1814 return 0;
1815}
1816
1817static int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,
1818 struct snd_ctl_elem_value *ucontrol)
1819{
1820 /*
1821 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1822 */
1823 u32 h_control = kcontrol->private_value;
1824 short gain;
1825
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001826 hpi_handle_error(hpi_tuner_get_gain(h_control, &gain));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001827 ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
1828
1829 return 0;
1830}
1831
1832static int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,
1833 struct snd_ctl_elem_value *ucontrol)
1834{
1835 /*
1836 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1837 */
1838 u32 h_control = kcontrol->private_value;
1839 short gain;
1840
1841 gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001842 hpi_handle_error(hpi_tuner_set_gain(h_control, gain));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001843
1844 return 1;
1845}
1846
1847/* Band */
1848
1849static int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,
1850 u16 *band_list, u32 len) {
1851 u32 h_control = kcontrol->private_value;
1852 u16 err = 0;
1853 u32 i;
1854
1855 for (i = 0; i < len; i++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001856 err = hpi_tuner_query_band(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001857 h_control, i, &band_list[i]);
1858 if (err != 0)
1859 break;
1860 }
1861
1862 if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX))
1863 return -EIO;
1864
1865 return i;
1866}
1867
1868static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
1869 struct snd_ctl_elem_info *uinfo)
1870{
1871 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1872 int num_bands = 0;
1873
1874 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1875 HPI_TUNER_BAND_LAST);
1876
1877 if (num_bands < 0)
1878 return num_bands;
1879
1880 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1881 uinfo->count = 1;
1882 uinfo->value.enumerated.items = num_bands;
1883
1884 if (num_bands > 0) {
1885 if (uinfo->value.enumerated.item >=
1886 uinfo->value.enumerated.items)
1887 uinfo->value.enumerated.item =
1888 uinfo->value.enumerated.items - 1;
1889
1890 strcpy(uinfo->value.enumerated.name,
1891 asihpi_tuner_band_names[
1892 tuner_bands[uinfo->value.enumerated.item]]);
1893
1894 }
1895 return 0;
1896}
1897
1898static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
1899 struct snd_ctl_elem_value *ucontrol)
1900{
1901 u32 h_control = kcontrol->private_value;
1902 /*
1903 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1904 */
1905 u16 band, idx;
1906 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1907 u32 num_bands = 0;
1908
1909 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1910 HPI_TUNER_BAND_LAST);
1911
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001912 hpi_handle_error(hpi_tuner_get_band(h_control, &band));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001913
1914 ucontrol->value.enumerated.item[0] = -1;
1915 for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
1916 if (tuner_bands[idx] == band) {
1917 ucontrol->value.enumerated.item[0] = idx;
1918 break;
1919 }
1920
1921 return 0;
1922}
1923
1924static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
1925 struct snd_ctl_elem_value *ucontrol)
1926{
1927 /*
1928 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1929 */
1930 u32 h_control = kcontrol->private_value;
1931 u16 band;
1932 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1933 u32 num_bands = 0;
1934
1935 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1936 HPI_TUNER_BAND_LAST);
1937
1938 band = tuner_bands[ucontrol->value.enumerated.item[0]];
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001939 hpi_handle_error(hpi_tuner_set_band(h_control, band));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001940
1941 return 1;
1942}
1943
1944/* Freq */
1945
1946static int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,
1947 struct snd_ctl_elem_info *uinfo)
1948{
1949 u32 h_control = kcontrol->private_value;
1950 u16 err;
1951 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1952 u16 num_bands = 0, band_iter, idx;
1953 u32 freq_range[3], temp_freq_range[3];
1954
1955 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1956 HPI_TUNER_BAND_LAST);
1957
1958 freq_range[0] = INT_MAX;
1959 freq_range[1] = 0;
1960 freq_range[2] = INT_MAX;
1961
1962 for (band_iter = 0; band_iter < num_bands; band_iter++) {
1963 for (idx = 0; idx < 3; idx++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001964 err = hpi_tuner_query_frequency(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001965 idx, tuner_bands[band_iter],
1966 &temp_freq_range[idx]);
1967 if (err != 0)
1968 return err;
1969 }
1970
1971 /* skip band with bogus stepping */
1972 if (temp_freq_range[2] <= 0)
1973 continue;
1974
1975 if (temp_freq_range[0] < freq_range[0])
1976 freq_range[0] = temp_freq_range[0];
1977 if (temp_freq_range[1] > freq_range[1])
1978 freq_range[1] = temp_freq_range[1];
1979 if (temp_freq_range[2] < freq_range[2])
1980 freq_range[2] = temp_freq_range[2];
1981 }
1982
1983 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1984 uinfo->count = 1;
1985 uinfo->value.integer.min = ((int)freq_range[0]);
1986 uinfo->value.integer.max = ((int)freq_range[1]);
1987 uinfo->value.integer.step = ((int)freq_range[2]);
1988 return 0;
1989}
1990
1991static int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,
1992 struct snd_ctl_elem_value *ucontrol)
1993{
1994 u32 h_control = kcontrol->private_value;
1995 u32 freq;
1996
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001997 hpi_handle_error(hpi_tuner_get_frequency(h_control, &freq));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001998 ucontrol->value.integer.value[0] = freq;
1999
2000 return 0;
2001}
2002
2003static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,
2004 struct snd_ctl_elem_value *ucontrol)
2005{
2006 u32 h_control = kcontrol->private_value;
2007 u32 freq;
2008
2009 freq = ucontrol->value.integer.value[0];
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002010 hpi_handle_error(hpi_tuner_set_frequency(h_control, freq));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002011
2012 return 1;
2013}
2014
2015/* Tuner control group initializer */
2016static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
2017 struct hpi_control *hpi_ctl)
2018{
2019 struct snd_card *card = asihpi->card;
2020 struct snd_kcontrol_new snd_control;
2021
2022 snd_control.private_value = hpi_ctl->h_control;
2023 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2024
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002025 if (!hpi_tuner_get_gain(hpi_ctl->h_control, NULL)) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002026 asihpi_ctl_init(&snd_control, hpi_ctl, "Gain");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002027 snd_control.info = snd_asihpi_tuner_gain_info;
2028 snd_control.get = snd_asihpi_tuner_gain_get;
2029 snd_control.put = snd_asihpi_tuner_gain_put;
2030
2031 if (ctl_add(card, &snd_control, asihpi) < 0)
2032 return -EINVAL;
2033 }
2034
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002035 asihpi_ctl_init(&snd_control, hpi_ctl, "Band");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002036 snd_control.info = snd_asihpi_tuner_band_info;
2037 snd_control.get = snd_asihpi_tuner_band_get;
2038 snd_control.put = snd_asihpi_tuner_band_put;
2039
2040 if (ctl_add(card, &snd_control, asihpi) < 0)
2041 return -EINVAL;
2042
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002043 asihpi_ctl_init(&snd_control, hpi_ctl, "Freq");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002044 snd_control.info = snd_asihpi_tuner_freq_info;
2045 snd_control.get = snd_asihpi_tuner_freq_get;
2046 snd_control.put = snd_asihpi_tuner_freq_put;
2047
2048 return ctl_add(card, &snd_control, asihpi);
2049}
2050
2051/*------------------------------------------------------------
2052 Meter controls
2053 ------------------------------------------------------------*/
2054static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,
2055 struct snd_ctl_elem_info *uinfo)
2056{
2057 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2058 uinfo->count = HPI_MAX_CHANNELS;
2059 uinfo->value.integer.min = 0;
2060 uinfo->value.integer.max = 0x7FFFFFFF;
2061 return 0;
2062}
2063
2064/* linear values for 10dB steps */
2065static int log2lin[] = {
2066 0x7FFFFFFF, /* 0dB */
2067 679093956,
2068 214748365,
2069 67909396,
2070 21474837,
2071 6790940,
2072 2147484, /* -60dB */
2073 679094,
2074 214748, /* -80 */
2075 67909,
2076 21475, /* -100 */
2077 6791,
2078 2147,
2079 679,
2080 214,
2081 68,
2082 21,
2083 7,
2084 2
2085};
2086
2087static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,
2088 struct snd_ctl_elem_value *ucontrol)
2089{
2090 u32 h_control = kcontrol->private_value;
2091 short an_gain_mB[HPI_MAX_CHANNELS], i;
2092 u16 err;
2093
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002094 err = hpi_meter_get_peak(h_control, an_gain_mB);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002095
2096 for (i = 0; i < HPI_MAX_CHANNELS; i++) {
2097 if (err) {
2098 ucontrol->value.integer.value[i] = 0;
2099 } else if (an_gain_mB[i] >= 0) {
2100 ucontrol->value.integer.value[i] =
2101 an_gain_mB[i] << 16;
2102 } else {
2103 /* -ve is log value in millibels < -60dB,
2104 * convert to (roughly!) linear,
2105 */
2106 ucontrol->value.integer.value[i] =
2107 log2lin[an_gain_mB[i] / -1000];
2108 }
2109 }
2110 return 0;
2111}
2112
2113static int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,
2114 struct hpi_control *hpi_ctl, int subidx)
2115{
2116 struct snd_card *card = asihpi->card;
2117 struct snd_kcontrol_new snd_control;
2118
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002119 asihpi_ctl_init(&snd_control, hpi_ctl, "Meter");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002120 snd_control.access =
2121 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2122 snd_control.info = snd_asihpi_meter_info;
2123 snd_control.get = snd_asihpi_meter_get;
2124
2125 snd_control.index = subidx;
2126
2127 return ctl_add(card, &snd_control, asihpi);
2128}
2129
2130/*------------------------------------------------------------
2131 Multiplexer controls
2132 ------------------------------------------------------------*/
2133static int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)
2134{
2135 u32 h_control = snd_control->private_value;
2136 struct hpi_control hpi_ctl;
2137 int s, err;
2138 for (s = 0; s < 32; s++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002139 err = hpi_multiplexer_query_source(h_control, s,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002140 &hpi_ctl.
2141 src_node_type,
2142 &hpi_ctl.
2143 src_node_index);
2144 if (err)
2145 break;
2146 }
2147 return s;
2148}
2149
2150static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
2151 struct snd_ctl_elem_info *uinfo)
2152{
2153 int err;
2154 u16 src_node_type, src_node_index;
2155 u32 h_control = kcontrol->private_value;
2156
2157 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2158 uinfo->count = 1;
2159 uinfo->value.enumerated.items =
2160 snd_card_asihpi_mux_count_sources(kcontrol);
2161
2162 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2163 uinfo->value.enumerated.item =
2164 uinfo->value.enumerated.items - 1;
2165
2166 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002167 hpi_multiplexer_query_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002168 uinfo->value.enumerated.item,
2169 &src_node_type, &src_node_index);
2170
2171 sprintf(uinfo->value.enumerated.name, "%s %d",
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12002172 asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002173 src_node_index);
2174 return 0;
2175}
2176
2177static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
2178 struct snd_ctl_elem_value *ucontrol)
2179{
2180 u32 h_control = kcontrol->private_value;
2181 u16 source_type, source_index;
2182 u16 src_node_type, src_node_index;
2183 int s;
2184
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002185 hpi_handle_error(hpi_multiplexer_get_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002186 &source_type, &source_index));
2187 /* Should cache this search result! */
2188 for (s = 0; s < 256; s++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002189 if (hpi_multiplexer_query_source(h_control, s,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002190 &src_node_type, &src_node_index))
2191 break;
2192
2193 if ((source_type == src_node_type)
2194 && (source_index == src_node_index)) {
2195 ucontrol->value.enumerated.item[0] = s;
2196 return 0;
2197 }
2198 }
2199 snd_printd(KERN_WARNING
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002200 "Control %x failed to match mux source %hu %hu\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002201 h_control, source_type, source_index);
2202 ucontrol->value.enumerated.item[0] = 0;
2203 return 0;
2204}
2205
2206static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,
2207 struct snd_ctl_elem_value *ucontrol)
2208{
2209 int change;
2210 u32 h_control = kcontrol->private_value;
2211 u16 source_type, source_index;
2212 u16 e;
2213
2214 change = 1;
2215
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002216 e = hpi_multiplexer_query_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002217 ucontrol->value.enumerated.item[0],
2218 &source_type, &source_index);
2219 if (!e)
2220 hpi_handle_error(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002221 hpi_multiplexer_set_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002222 source_type, source_index));
2223 return change;
2224}
2225
2226
2227static int __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
2228 struct hpi_control *hpi_ctl)
2229{
2230 struct snd_card *card = asihpi->card;
2231 struct snd_kcontrol_new snd_control;
2232
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002233 asihpi_ctl_init(&snd_control, hpi_ctl, "Route");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002234 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2235 snd_control.info = snd_asihpi_mux_info;
2236 snd_control.get = snd_asihpi_mux_get;
2237 snd_control.put = snd_asihpi_mux_put;
2238
2239 return ctl_add(card, &snd_control, asihpi);
2240
2241}
2242
2243/*------------------------------------------------------------
2244 Channel mode controls
2245 ------------------------------------------------------------*/
2246static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
2247 struct snd_ctl_elem_info *uinfo)
2248{
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002249 static const char * const mode_names[HPI_CHANNEL_MODE_LAST + 1] = {
2250 "invalid",
2251 "Normal", "Swap",
2252 "From Left", "From Right",
2253 "To Left", "To Right"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002254 };
2255
2256 u32 h_control = kcontrol->private_value;
2257 u16 mode;
2258 int i;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002259 u16 mode_map[6];
2260 int valid_modes = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002261
2262 /* HPI channel mode values can be from 1 to 6
2263 Some adapters only support a contiguous subset
2264 */
2265 for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002266 if (!hpi_channel_mode_query_mode(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002267 h_control, i, &mode)) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002268 mode_map[valid_modes] = mode;
2269 valid_modes++;
2270 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002271
2272 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2273 uinfo->count = 1;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002274 uinfo->value.enumerated.items = valid_modes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002275
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002276 if (uinfo->value.enumerated.item >= valid_modes)
2277 uinfo->value.enumerated.item = valid_modes - 1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002278
2279 strcpy(uinfo->value.enumerated.name,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002280 mode_names[mode_map[uinfo->value.enumerated.item]]);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002281
2282 return 0;
2283}
2284
2285static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
2286 struct snd_ctl_elem_value *ucontrol)
2287{
2288 u32 h_control = kcontrol->private_value;
2289 u16 mode;
2290
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002291 if (hpi_channel_mode_get(h_control, &mode))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002292 mode = 1;
2293
2294 ucontrol->value.enumerated.item[0] = mode - 1;
2295
2296 return 0;
2297}
2298
2299static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,
2300 struct snd_ctl_elem_value *ucontrol)
2301{
2302 int change;
2303 u32 h_control = kcontrol->private_value;
2304
2305 change = 1;
2306
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002307 hpi_handle_error(hpi_channel_mode_set(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002308 ucontrol->value.enumerated.item[0] + 1));
2309 return change;
2310}
2311
2312
2313static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
2314 struct hpi_control *hpi_ctl)
2315{
2316 struct snd_card *card = asihpi->card;
2317 struct snd_kcontrol_new snd_control;
2318
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002319 asihpi_ctl_init(&snd_control, hpi_ctl, "Mode");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002320 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2321 snd_control.info = snd_asihpi_cmode_info;
2322 snd_control.get = snd_asihpi_cmode_get;
2323 snd_control.put = snd_asihpi_cmode_put;
2324
2325 return ctl_add(card, &snd_control, asihpi);
2326}
2327
2328/*------------------------------------------------------------
2329 Sampleclock source controls
2330 ------------------------------------------------------------*/
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002331static char *sampleclock_sources[MAX_CLOCKSOURCES] = {
2332 "N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
2333 "SMPTE", "Digital1", "Auto", "Network", "Invalid",
2334 "Prev Module",
2335 "Digital2", "Digital3", "Digital4", "Digital5",
2336 "Digital6", "Digital7", "Digital8"};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002337
2338static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
2339 struct snd_ctl_elem_info *uinfo)
2340{
2341 struct snd_card_asihpi *asihpi =
2342 (struct snd_card_asihpi *)(kcontrol->private_data);
2343 struct clk_cache *clkcache = &asihpi->cc;
2344 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2345 uinfo->count = 1;
2346 uinfo->value.enumerated.items = clkcache->count;
2347
2348 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2349 uinfo->value.enumerated.item =
2350 uinfo->value.enumerated.items - 1;
2351
2352 strcpy(uinfo->value.enumerated.name,
2353 clkcache->s[uinfo->value.enumerated.item].name);
2354 return 0;
2355}
2356
2357static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
2358 struct snd_ctl_elem_value *ucontrol)
2359{
2360 struct snd_card_asihpi *asihpi =
2361 (struct snd_card_asihpi *)(kcontrol->private_data);
2362 struct clk_cache *clkcache = &asihpi->cc;
2363 u32 h_control = kcontrol->private_value;
2364 u16 source, srcindex = 0;
2365 int i;
2366
2367 ucontrol->value.enumerated.item[0] = 0;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002368 if (hpi_sample_clock_get_source(h_control, &source))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002369 source = 0;
2370
2371 if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002372 if (hpi_sample_clock_get_source_index(h_control, &srcindex))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002373 srcindex = 0;
2374
2375 for (i = 0; i < clkcache->count; i++)
2376 if ((clkcache->s[i].source == source) &&
2377 (clkcache->s[i].index == srcindex))
2378 break;
2379
2380 ucontrol->value.enumerated.item[0] = i;
2381
2382 return 0;
2383}
2384
2385static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
2386 struct snd_ctl_elem_value *ucontrol)
2387{
2388 struct snd_card_asihpi *asihpi =
2389 (struct snd_card_asihpi *)(kcontrol->private_data);
2390 struct clk_cache *clkcache = &asihpi->cc;
2391 int change, item;
2392 u32 h_control = kcontrol->private_value;
2393
2394 change = 1;
2395 item = ucontrol->value.enumerated.item[0];
2396 if (item >= clkcache->count)
2397 item = clkcache->count-1;
2398
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002399 hpi_handle_error(hpi_sample_clock_set_source(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002400 h_control, clkcache->s[item].source));
2401
2402 if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002403 hpi_handle_error(hpi_sample_clock_set_source_index(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002404 h_control, clkcache->s[item].index));
2405 return change;
2406}
2407
2408/*------------------------------------------------------------
2409 Clkrate controls
2410 ------------------------------------------------------------*/
2411/* Need to change this to enumerated control with list of rates */
2412static int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol,
2413 struct snd_ctl_elem_info *uinfo)
2414{
2415 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2416 uinfo->count = 1;
2417 uinfo->value.integer.min = 8000;
2418 uinfo->value.integer.max = 192000;
2419 uinfo->value.integer.step = 100;
2420
2421 return 0;
2422}
2423
2424static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,
2425 struct snd_ctl_elem_value *ucontrol)
2426{
2427 u32 h_control = kcontrol->private_value;
2428 u32 rate;
2429 u16 e;
2430
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002431 e = hpi_sample_clock_get_local_rate(h_control, &rate);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002432 if (!e)
2433 ucontrol->value.integer.value[0] = rate;
2434 else
2435 ucontrol->value.integer.value[0] = 0;
2436 return 0;
2437}
2438
2439static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,
2440 struct snd_ctl_elem_value *ucontrol)
2441{
2442 int change;
2443 u32 h_control = kcontrol->private_value;
2444
2445 /* change = asihpi->mixer_clkrate[addr][0] != left ||
2446 asihpi->mixer_clkrate[addr][1] != right;
2447 */
2448 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002449 hpi_handle_error(hpi_sample_clock_set_local_rate(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002450 ucontrol->value.integer.value[0]));
2451 return change;
2452}
2453
2454static int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol,
2455 struct snd_ctl_elem_info *uinfo)
2456{
2457 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2458 uinfo->count = 1;
2459 uinfo->value.integer.min = 8000;
2460 uinfo->value.integer.max = 192000;
2461 uinfo->value.integer.step = 100;
2462
2463 return 0;
2464}
2465
2466static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
2467 struct snd_ctl_elem_value *ucontrol)
2468{
2469 u32 h_control = kcontrol->private_value;
2470 u32 rate;
2471 u16 e;
2472
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002473 e = hpi_sample_clock_get_sample_rate(h_control, &rate);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002474 if (!e)
2475 ucontrol->value.integer.value[0] = rate;
2476 else
2477 ucontrol->value.integer.value[0] = 0;
2478 return 0;
2479}
2480
2481static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
2482 struct hpi_control *hpi_ctl)
2483{
2484 struct snd_card *card = asihpi->card;
2485 struct snd_kcontrol_new snd_control;
2486
2487 struct clk_cache *clkcache = &asihpi->cc;
2488 u32 hSC = hpi_ctl->h_control;
2489 int has_aes_in = 0;
2490 int i, j;
2491 u16 source;
2492
2493 snd_control.private_value = hpi_ctl->h_control;
2494
2495 clkcache->has_local = 0;
2496
2497 for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002498 if (hpi_sample_clock_query_source(hSC,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002499 i, &source))
2500 break;
2501 clkcache->s[i].source = source;
2502 clkcache->s[i].index = 0;
2503 clkcache->s[i].name = sampleclock_sources[source];
2504 if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2505 has_aes_in = 1;
2506 if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL)
2507 clkcache->has_local = 1;
2508 }
2509 if (has_aes_in)
2510 /* already will have picked up index 0 above */
2511 for (j = 1; j < 8; j++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002512 if (hpi_sample_clock_query_source_index(hSC,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002513 j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,
2514 &source))
2515 break;
2516 clkcache->s[i].source =
2517 HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT;
2518 clkcache->s[i].index = j;
2519 clkcache->s[i].name = sampleclock_sources[
2520 j+HPI_SAMPLECLOCK_SOURCE_LAST];
2521 i++;
2522 }
2523 clkcache->count = i;
2524
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002525 asihpi_ctl_init(&snd_control, hpi_ctl, "Source");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002526 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2527 snd_control.info = snd_asihpi_clksrc_info;
2528 snd_control.get = snd_asihpi_clksrc_get;
2529 snd_control.put = snd_asihpi_clksrc_put;
2530 if (ctl_add(card, &snd_control, asihpi) < 0)
2531 return -EINVAL;
2532
2533
2534 if (clkcache->has_local) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002535 asihpi_ctl_init(&snd_control, hpi_ctl, "Localrate");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002536 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2537 snd_control.info = snd_asihpi_clklocal_info;
2538 snd_control.get = snd_asihpi_clklocal_get;
2539 snd_control.put = snd_asihpi_clklocal_put;
2540
2541
2542 if (ctl_add(card, &snd_control, asihpi) < 0)
2543 return -EINVAL;
2544 }
2545
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002546 asihpi_ctl_init(&snd_control, hpi_ctl, "Rate");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002547 snd_control.access =
2548 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2549 snd_control.info = snd_asihpi_clkrate_info;
2550 snd_control.get = snd_asihpi_clkrate_get;
2551
2552 return ctl_add(card, &snd_control, asihpi);
2553}
2554/*------------------------------------------------------------
2555 Mixer
2556 ------------------------------------------------------------*/
2557
2558static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
2559{
2560 struct snd_card *card = asihpi->card;
2561 unsigned int idx = 0;
2562 unsigned int subindex = 0;
2563 int err;
2564 struct hpi_control hpi_ctl, prev_ctl;
2565
2566 if (snd_BUG_ON(!asihpi))
2567 return -EINVAL;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002568 strcpy(card->mixername, "Asihpi Mixer");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002569
2570 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002571 hpi_mixer_open(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002572 &asihpi->h_mixer);
2573 hpi_handle_error(err);
2574 if (err)
2575 return -err;
2576
Takashi Iwai21896bc2010-06-02 12:08:37 +02002577 memset(&prev_ctl, 0, sizeof(prev_ctl));
2578 prev_ctl.control_type = -1;
2579
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002580 for (idx = 0; idx < 2000; idx++) {
2581 err = hpi_mixer_get_control_by_index(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002582 asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002583 idx,
2584 &hpi_ctl.src_node_type,
2585 &hpi_ctl.src_node_index,
2586 &hpi_ctl.dst_node_type,
2587 &hpi_ctl.dst_node_index,
2588 &hpi_ctl.control_type,
2589 &hpi_ctl.h_control);
2590 if (err) {
2591 if (err == HPI_ERROR_CONTROL_DISABLED) {
2592 if (mixer_dump)
2593 snd_printk(KERN_INFO
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002594 "Disabled HPI Control(%d)\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002595 idx);
2596 continue;
2597 } else
2598 break;
2599
2600 }
2601
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12002602 hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;
2603 hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002604
2605 /* ASI50xx in SSX mode has multiple meters on the same node.
2606 Use subindex to create distinct ALSA controls
2607 for any duplicated controls.
2608 */
2609 if ((hpi_ctl.control_type == prev_ctl.control_type) &&
2610 (hpi_ctl.src_node_type == prev_ctl.src_node_type) &&
2611 (hpi_ctl.src_node_index == prev_ctl.src_node_index) &&
2612 (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) &&
2613 (hpi_ctl.dst_node_index == prev_ctl.dst_node_index))
2614 subindex++;
2615 else
2616 subindex = 0;
2617
2618 prev_ctl = hpi_ctl;
2619
2620 switch (hpi_ctl.control_type) {
2621 case HPI_CONTROL_VOLUME:
2622 err = snd_asihpi_volume_add(asihpi, &hpi_ctl);
2623 break;
2624 case HPI_CONTROL_LEVEL:
2625 err = snd_asihpi_level_add(asihpi, &hpi_ctl);
2626 break;
2627 case HPI_CONTROL_MULTIPLEXER:
2628 err = snd_asihpi_mux_add(asihpi, &hpi_ctl);
2629 break;
2630 case HPI_CONTROL_CHANNEL_MODE:
2631 err = snd_asihpi_cmode_add(asihpi, &hpi_ctl);
2632 break;
2633 case HPI_CONTROL_METER:
2634 err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex);
2635 break;
2636 case HPI_CONTROL_SAMPLECLOCK:
2637 err = snd_asihpi_sampleclock_add(
2638 asihpi, &hpi_ctl);
2639 break;
2640 case HPI_CONTROL_CONNECTION: /* ignore these */
2641 continue;
2642 case HPI_CONTROL_TUNER:
2643 err = snd_asihpi_tuner_add(asihpi, &hpi_ctl);
2644 break;
2645 case HPI_CONTROL_AESEBU_TRANSMITTER:
2646 err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl);
2647 break;
2648 case HPI_CONTROL_AESEBU_RECEIVER:
2649 err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl);
2650 break;
2651 case HPI_CONTROL_VOX:
2652 case HPI_CONTROL_BITSTREAM:
2653 case HPI_CONTROL_MICROPHONE:
2654 case HPI_CONTROL_PARAMETRIC_EQ:
2655 case HPI_CONTROL_COMPANDER:
2656 default:
2657 if (mixer_dump)
2658 snd_printk(KERN_INFO
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002659 "Untranslated HPI Control"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002660 "(%d) %d %d %d %d %d\n",
2661 idx,
2662 hpi_ctl.control_type,
2663 hpi_ctl.src_node_type,
2664 hpi_ctl.src_node_index,
2665 hpi_ctl.dst_node_type,
2666 hpi_ctl.dst_node_index);
2667 continue;
2668 };
2669 if (err < 0)
2670 return err;
2671 }
2672 if (HPI_ERROR_INVALID_OBJ_INDEX != err)
2673 hpi_handle_error(err);
2674
2675 snd_printk(KERN_INFO "%d mixer controls found\n", idx);
2676
2677 return 0;
2678}
2679
2680/*------------------------------------------------------------
2681 /proc interface
2682 ------------------------------------------------------------*/
2683
2684static void
2685snd_asihpi_proc_read(struct snd_info_entry *entry,
2686 struct snd_info_buffer *buffer)
2687{
2688 struct snd_card_asihpi *asihpi = entry->private_data;
2689 u16 version;
2690 u32 h_control;
2691 u32 rate = 0;
2692 u16 source = 0;
2693 int err;
2694
2695 snd_iprintf(buffer, "ASIHPI driver proc file\n");
2696 snd_iprintf(buffer,
2697 "adapter ID=%4X\n_index=%d\n"
2698 "num_outstreams=%d\n_num_instreams=%d\n",
2699 asihpi->type, asihpi->adapter_index,
2700 asihpi->num_outstreams, asihpi->num_instreams);
2701
2702 version = asihpi->version;
2703 snd_iprintf(buffer,
2704 "serial#=%d\n_hw version %c%d\nDSP code version %03d\n",
2705 asihpi->serial_number, ((version >> 3) & 0xf) + 'A',
2706 version & 0x7,
2707 ((version >> 13) * 100) + ((version >> 7) & 0x3f));
2708
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002709 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002710 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2711 HPI_CONTROL_SAMPLECLOCK, &h_control);
2712
2713 if (!err) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002714 err = hpi_sample_clock_get_sample_rate(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002715 h_control, &rate);
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002716 err += hpi_sample_clock_get_source(h_control, &source);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002717
2718 if (!err)
2719 snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n",
2720 rate, sampleclock_sources[source]);
2721 }
2722
2723}
2724
2725
2726static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
2727{
2728 struct snd_info_entry *entry;
2729
2730 if (!snd_card_proc_new(asihpi->card, "info", &entry))
2731 snd_info_set_text_ops(entry, asihpi, snd_asihpi_proc_read);
2732}
2733
2734/*------------------------------------------------------------
2735 HWDEP
2736 ------------------------------------------------------------*/
2737
2738static int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file)
2739{
2740 if (enable_hpi_hwdep)
2741 return 0;
2742 else
2743 return -ENODEV;
2744
2745}
2746
2747static int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file)
2748{
2749 if (enable_hpi_hwdep)
2750 return asihpi_hpi_release(file);
2751 else
2752 return -ENODEV;
2753}
2754
2755static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
2756 unsigned int cmd, unsigned long arg)
2757{
2758 if (enable_hpi_hwdep)
2759 return asihpi_hpi_ioctl(file, cmd, arg);
2760 else
2761 return -ENODEV;
2762}
2763
2764
2765/* results in /dev/snd/hwC#D0 file for each card with index #
2766 also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
2767*/
2768static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
2769 int device, struct snd_hwdep **rhwdep)
2770{
2771 struct snd_hwdep *hw;
2772 int err;
2773
2774 if (rhwdep)
2775 *rhwdep = NULL;
2776 err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
2777 if (err < 0)
2778 return err;
2779 strcpy(hw->name, "asihpi (HPI)");
2780 hw->iface = SNDRV_HWDEP_IFACE_LAST;
2781 hw->ops.open = snd_asihpi_hpi_open;
2782 hw->ops.ioctl = snd_asihpi_hpi_ioctl;
2783 hw->ops.release = snd_asihpi_hpi_release;
2784 hw->private_data = asihpi;
2785 if (rhwdep)
2786 *rhwdep = hw;
2787 return 0;
2788}
2789
2790/*------------------------------------------------------------
2791 CARD
2792 ------------------------------------------------------------*/
2793static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
2794 const struct pci_device_id *pci_id)
2795{
2796 int err;
2797
2798 u16 version;
2799 int pcm_substreams;
2800
2801 struct hpi_adapter *hpi_card;
2802 struct snd_card *card;
2803 struct snd_card_asihpi *asihpi;
2804
2805 u32 h_control;
2806 u32 h_stream;
2807
2808 static int dev;
2809 if (dev >= SNDRV_CARDS)
2810 return -ENODEV;
2811
2812 /* Should this be enable[hpi_card->index] ? */
2813 if (!enable[dev]) {
2814 dev++;
2815 return -ENOENT;
2816 }
2817
2818 err = asihpi_adapter_probe(pci_dev, pci_id);
2819 if (err < 0)
2820 return err;
2821
2822 hpi_card = pci_get_drvdata(pci_dev);
2823 /* first try to give the card the same index as its hardware index */
2824 err = snd_card_create(hpi_card->index,
2825 id[hpi_card->index], THIS_MODULE,
2826 sizeof(struct snd_card_asihpi),
2827 &card);
2828 if (err < 0) {
2829 /* if that fails, try the default index==next available */
2830 err =
2831 snd_card_create(index[dev], id[dev],
2832 THIS_MODULE,
2833 sizeof(struct snd_card_asihpi),
2834 &card);
2835 if (err < 0)
2836 return err;
2837 snd_printk(KERN_WARNING
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002838 "**** WARNING **** Adapter index %d->ALSA index %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002839 hpi_card->index, card->number);
2840 }
2841
Eliot Blennerhassett12253672011-02-10 17:26:10 +13002842 snd_card_set_dev(card, &pci_dev->dev);
2843
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002844 asihpi = (struct snd_card_asihpi *) card->private_data;
2845 asihpi->card = card;
Eliot Blennerhassett12253672011-02-10 17:26:10 +13002846 asihpi->pci = pci_dev;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002847 asihpi->adapter_index = hpi_card->index;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002848 hpi_handle_error(hpi_adapter_get_info(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002849 asihpi->adapter_index,
2850 &asihpi->num_outstreams,
2851 &asihpi->num_instreams,
2852 &asihpi->version,
2853 &asihpi->serial_number, &asihpi->type));
2854
2855 version = asihpi->version;
2856 snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d "
2857 "num_instreams=%d S/N=%d\n"
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002858 "Hw Version %c%d DSP code version %03d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002859 asihpi->type, asihpi->adapter_index,
2860 asihpi->num_outstreams,
2861 asihpi->num_instreams, asihpi->serial_number,
2862 ((version >> 3) & 0xf) + 'A',
2863 version & 0x7,
2864 ((version >> 13) * 100) + ((version >> 7) & 0x3f));
2865
2866 pcm_substreams = asihpi->num_outstreams;
2867 if (pcm_substreams < asihpi->num_instreams)
2868 pcm_substreams = asihpi->num_instreams;
2869
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002870 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002871 HPI_ADAPTER_PROPERTY_CAPS1,
2872 NULL, &asihpi->support_grouping);
2873 if (err)
2874 asihpi->support_grouping = 0;
2875
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002876 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002877 HPI_ADAPTER_PROPERTY_CAPS2,
2878 &asihpi->support_mrx, NULL);
2879 if (err)
2880 asihpi->support_mrx = 0;
2881
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002882 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002883 HPI_ADAPTER_PROPERTY_INTERVAL,
2884 NULL, &asihpi->update_interval_frames);
2885 if (err)
2886 asihpi->update_interval_frames = 512;
2887
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002888 hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002889 0, &h_stream));
2890
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002891 err = hpi_instream_host_buffer_free(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002892 asihpi->support_mmap = (!err);
2893
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002894 hpi_handle_error(hpi_instream_close(h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002895
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002896 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002897 HPI_ADAPTER_PROPERTY_CURCHANNELS,
2898 &asihpi->in_max_chans, &asihpi->out_max_chans);
2899 if (err) {
2900 asihpi->in_max_chans = 2;
2901 asihpi->out_max_chans = 2;
2902 }
2903
2904 snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n",
2905 asihpi->support_mmap,
2906 asihpi->support_grouping,
2907 asihpi->support_mrx
2908 );
2909
2910
2911 err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams);
2912 if (err < 0) {
2913 snd_printk(KERN_ERR "pcm_new failed\n");
2914 goto __nodev;
2915 }
2916 err = snd_card_asihpi_mixer_new(asihpi);
2917 if (err < 0) {
2918 snd_printk(KERN_ERR "mixer_new failed\n");
2919 goto __nodev;
2920 }
2921
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002922 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002923 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2924 HPI_CONTROL_SAMPLECLOCK, &h_control);
2925
2926 if (!err)
2927 err = hpi_sample_clock_set_local_rate(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002928 h_control, adapter_fs);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002929
2930 snd_asihpi_proc_init(asihpi);
2931
2932 /* always create, can be enabled or disabled dynamically
2933 by enable_hwdep module param*/
2934 snd_asihpi_hpi_new(asihpi, 0, NULL);
2935
2936 if (asihpi->support_mmap)
2937 strcpy(card->driver, "ASIHPI-MMAP");
2938 else
2939 strcpy(card->driver, "ASIHPI");
2940
2941 sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
2942 sprintf(card->longname, "%s %i",
2943 card->shortname, asihpi->adapter_index);
2944 err = snd_card_register(card);
2945 if (!err) {
2946 hpi_card->snd_card_asihpi = card;
2947 dev++;
2948 return 0;
2949 }
2950__nodev:
2951 snd_card_free(card);
2952 snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err);
2953 return err;
2954
2955}
2956
2957static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev)
2958{
2959 struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev);
2960
2961 snd_card_free(hpi_card->snd_card_asihpi);
2962 hpi_card->snd_card_asihpi = NULL;
2963 asihpi_adapter_remove(pci_dev);
2964}
2965
2966static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = {
2967 {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
2968 HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2969 (kernel_ulong_t)HPI_6205},
2970 {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
2971 HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2972 (kernel_ulong_t)HPI_6000},
2973 {0,}
2974};
2975MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
2976
2977static struct pci_driver driver = {
2978 .name = "asihpi",
2979 .id_table = asihpi_pci_tbl,
2980 .probe = snd_asihpi_probe,
2981 .remove = __devexit_p(snd_asihpi_remove),
2982#ifdef CONFIG_PM
2983/* .suspend = snd_asihpi_suspend,
2984 .resume = snd_asihpi_resume, */
2985#endif
2986};
2987
2988static int __init snd_asihpi_init(void)
2989{
2990 asihpi_init();
2991 return pci_register_driver(&driver);
2992}
2993
2994static void __exit snd_asihpi_exit(void)
2995{
2996
2997 pci_unregister_driver(&driver);
2998 asihpi_exit();
2999}
3000
3001module_init(snd_asihpi_init)
3002module_exit(snd_asihpi_exit)
3003