blob: c90d77ad681bd61cddc3062893aecb0aea94b5e6 [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);
Eliot Blennerhassett26aebef2011-03-25 15:25:47 +13001015
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001016 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001017 card->update_interval_frames * 2, UINT_MAX);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001018
1019 snd_pcm_set_sync(substream);
1020
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001021 VPRINTK1(KERN_INFO "playback open\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001022
1023 return 0;
1024}
1025
1026static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
1027{
1028 struct snd_pcm_runtime *runtime = substream->runtime;
1029 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1030
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001031 hpi_handle_error(hpi_outstream_close(dpcm->h_stream));
1032 VPRINTK1(KERN_INFO "playback close\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001033
1034 return 0;
1035}
1036
1037static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
1038 int channel,
1039 snd_pcm_uframes_t pos,
1040 void __user *src,
1041 snd_pcm_uframes_t count)
1042{
1043 struct snd_pcm_runtime *runtime = substream->runtime;
1044 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1045 unsigned int len;
1046
1047 len = frames_to_bytes(runtime, count);
1048
1049 if (copy_from_user(runtime->dma_area, src, len))
1050 return -EFAULT;
1051
1052 VPRINTK2(KERN_DEBUG "playback copy%d %u bytes\n",
1053 substream->number, len);
1054
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001055 hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001056 runtime->dma_area, len, &dpcm->format));
1057
Eliot Blennerhassett26aebef2011-03-25 15:25:47 +13001058 dpcm->pcm_buf_host_rw_ofs += len;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001059
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001060 return 0;
1061}
1062
1063static int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
1064 substream, int channel,
1065 snd_pcm_uframes_t pos,
1066 snd_pcm_uframes_t count)
1067{
Eliot Blennerhassett26aebef2011-03-25 15:25:47 +13001068 /* Usually writes silence to DMA buffer, which should be overwritten
1069 by real audio later. Our fifos cannot be overwritten, and are not
1070 free-running DMAs. Silence is output on fifo underflow.
1071 This callback is still required to allow the copy callback to be used.
1072 */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001073 return 0;
1074}
1075
1076static struct snd_pcm_ops snd_card_asihpi_playback_ops = {
1077 .open = snd_card_asihpi_playback_open,
1078 .close = snd_card_asihpi_playback_close,
1079 .ioctl = snd_card_asihpi_playback_ioctl,
1080 .hw_params = snd_card_asihpi_pcm_hw_params,
1081 .hw_free = snd_card_asihpi_hw_free,
1082 .prepare = snd_card_asihpi_playback_prepare,
1083 .trigger = snd_card_asihpi_trigger,
1084 .pointer = snd_card_asihpi_playback_pointer,
1085 .copy = snd_card_asihpi_playback_copy,
1086 .silence = snd_card_asihpi_playback_silence,
1087};
1088
1089static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
1090 .open = snd_card_asihpi_playback_open,
1091 .close = snd_card_asihpi_playback_close,
1092 .ioctl = snd_card_asihpi_playback_ioctl,
1093 .hw_params = snd_card_asihpi_pcm_hw_params,
1094 .hw_free = snd_card_asihpi_hw_free,
1095 .prepare = snd_card_asihpi_playback_prepare,
1096 .trigger = snd_card_asihpi_trigger,
1097 .pointer = snd_card_asihpi_playback_pointer,
1098};
1099
1100/***************************** CAPTURE OPS ****************/
1101static snd_pcm_uframes_t
1102snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
1103{
1104 struct snd_pcm_runtime *runtime = substream->runtime;
1105 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1106
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001107 VPRINTK2(KERN_INFO "capture pointer %d=%d\n",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001108 substream->number, dpcm->pcm_buf_dma_ofs);
1109 /* NOTE Unlike playback can't use actual samples_played
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001110 for the capture position, because those samples aren't yet in
1111 the local buffer available for reading.
1112 */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001113 return bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001114}
1115
1116static int snd_card_asihpi_capture_ioctl(struct snd_pcm_substream *substream,
1117 unsigned int cmd, void *arg)
1118{
1119 return snd_pcm_lib_ioctl(substream, cmd, arg);
1120}
1121
1122static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
1123{
1124 struct snd_pcm_runtime *runtime = substream->runtime;
1125 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1126
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001127 hpi_handle_error(hpi_instream_reset(dpcm->h_stream));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001128 dpcm->pcm_buf_host_rw_ofs = 0;
1129 dpcm->pcm_buf_dma_ofs = 0;
1130 dpcm->pcm_buf_elapsed_dma_ofs = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001131
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001132 VPRINTK1("Capture Prepare %d\n", substream->number);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001133 return 0;
1134}
1135
1136
1137
1138static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
1139 u32 h_stream,
1140 struct snd_pcm_hardware *pcmhw)
1141{
1142 struct hpi_format hpi_format;
1143 u16 format;
1144 u16 err;
1145 u32 h_control;
1146 u32 sample_rate = 48000;
1147
1148 /* on cards without SRC, must query at valid rate,
1149 maybe set by external sync */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001150 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001151 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
1152 HPI_CONTROL_SAMPLECLOCK, &h_control);
1153
1154 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001155 err = hpi_sample_clock_get_sample_rate(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001156 &sample_rate);
1157
1158 for (format = HPI_FORMAT_PCM8_UNSIGNED;
1159 format <= HPI_FORMAT_PCM24_SIGNED; format++) {
1160
1161 err = hpi_format_create(&hpi_format, 2, format,
1162 sample_rate, 128000, 0);
1163 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001164 err = hpi_instream_query_format(h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001165 &hpi_format);
1166 if (!err)
1167 pcmhw->formats |=
1168 (1ULL << hpi_to_alsa_formats[format]);
1169 }
1170}
1171
1172
1173static struct snd_pcm_hardware snd_card_asihpi_capture = {
1174 .channels_min = 1,
1175 .channels_max = 2,
1176 .buffer_bytes_max = BUFFER_BYTES_MAX,
1177 .period_bytes_min = PERIOD_BYTES_MIN,
1178 .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
1179 .periods_min = PERIODS_MIN,
1180 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
1181 .fifo_size = 0,
1182};
1183
1184static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
1185{
1186 struct snd_pcm_runtime *runtime = substream->runtime;
1187 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
1188 struct snd_card_asihpi_pcm *dpcm;
1189 int err;
1190
1191 dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
1192 if (dpcm == NULL)
1193 return -ENOMEM;
1194
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001195 VPRINTK1("hpi_instream_open adapter %d stream %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001196 card->adapter_index, substream->number);
1197
1198 err = hpi_handle_error(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001199 hpi_instream_open(card->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001200 substream->number, &dpcm->h_stream));
1201 if (err)
1202 kfree(dpcm);
1203 if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
1204 return -EBUSY;
1205 if (err)
1206 return -EIO;
1207
1208
1209 init_timer(&dpcm->timer);
1210 dpcm->timer.data = (unsigned long) dpcm;
1211 dpcm->timer.function = snd_card_asihpi_timer_function;
1212 dpcm->substream = substream;
1213 runtime->private_data = dpcm;
1214 runtime->private_free = snd_card_asihpi_runtime_free;
1215
1216 snd_card_asihpi_capture.channels_max = card->in_max_chans;
1217 snd_card_asihpi_capture_format(card, dpcm->h_stream,
1218 &snd_card_asihpi_capture);
1219 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture);
1220 snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED;
1221
1222 if (card->support_mmap)
1223 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
1224 SNDRV_PCM_INFO_MMAP_VALID;
1225
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001226 if (card->support_grouping)
1227 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
1228
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001229 runtime->hw = snd_card_asihpi_capture;
1230
1231 if (card->support_mmap)
1232 err = snd_pcm_hw_constraint_pow2(runtime, 0,
1233 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1234 if (err < 0)
1235 return err;
1236
1237 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1238 card->update_interval_frames);
1239 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1240 card->update_interval_frames * 2, UINT_MAX);
1241
1242 snd_pcm_set_sync(substream);
1243
1244 return 0;
1245}
1246
1247static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
1248{
1249 struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
1250
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001251 hpi_handle_error(hpi_instream_close(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001252 return 0;
1253}
1254
1255static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
1256 int channel, snd_pcm_uframes_t pos,
1257 void __user *dst, snd_pcm_uframes_t count)
1258{
1259 struct snd_pcm_runtime *runtime = substream->runtime;
1260 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001261 u32 len;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001262
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001263 len = frames_to_bytes(runtime, count);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001264
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001265 VPRINTK2(KERN_INFO "capture copy%d %d bytes\n", substream->number, len);
1266 hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001267 runtime->dma_area, len));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001268
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001269 dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001270
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001271 if (copy_to_user(dst, runtime->dma_area, len))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001272 return -EFAULT;
1273
1274 return 0;
1275}
1276
1277static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
1278 .open = snd_card_asihpi_capture_open,
1279 .close = snd_card_asihpi_capture_close,
1280 .ioctl = snd_card_asihpi_capture_ioctl,
1281 .hw_params = snd_card_asihpi_pcm_hw_params,
1282 .hw_free = snd_card_asihpi_hw_free,
1283 .prepare = snd_card_asihpi_capture_prepare,
1284 .trigger = snd_card_asihpi_trigger,
1285 .pointer = snd_card_asihpi_capture_pointer,
1286};
1287
1288static struct snd_pcm_ops snd_card_asihpi_capture_ops = {
1289 .open = snd_card_asihpi_capture_open,
1290 .close = snd_card_asihpi_capture_close,
1291 .ioctl = snd_card_asihpi_capture_ioctl,
1292 .hw_params = snd_card_asihpi_pcm_hw_params,
1293 .hw_free = snd_card_asihpi_hw_free,
1294 .prepare = snd_card_asihpi_capture_prepare,
1295 .trigger = snd_card_asihpi_trigger,
1296 .pointer = snd_card_asihpi_capture_pointer,
1297 .copy = snd_card_asihpi_capture_copy
1298};
1299
1300static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
1301 int device, int substreams)
1302{
1303 struct snd_pcm *pcm;
1304 int err;
1305
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001306 err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001307 asihpi->num_outstreams, asihpi->num_instreams,
1308 &pcm);
1309 if (err < 0)
1310 return err;
1311 /* pointer to ops struct is stored, dont change ops afterwards! */
1312 if (asihpi->support_mmap) {
1313 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1314 &snd_card_asihpi_playback_mmap_ops);
1315 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1316 &snd_card_asihpi_capture_mmap_ops);
1317 } else {
1318 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1319 &snd_card_asihpi_playback_ops);
1320 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1321 &snd_card_asihpi_capture_ops);
1322 }
1323
1324 pcm->private_data = asihpi;
1325 pcm->info_flags = 0;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001326 strcpy(pcm->name, "Asihpi PCM");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001327
1328 /*? do we want to emulate MMAP for non-BBM cards?
1329 Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
1330 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1331 snd_dma_pci_data(asihpi->pci),
1332 64*1024, BUFFER_BYTES_MAX);
1333
1334 return 0;
1335}
1336
1337/***************************** MIXER CONTROLS ****************/
1338struct hpi_control {
1339 u32 h_control;
1340 u16 control_type;
1341 u16 src_node_type;
1342 u16 src_node_index;
1343 u16 dst_node_type;
1344 u16 dst_node_index;
1345 u16 band;
1346 char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
1347};
1348
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001349static const char * const asihpi_tuner_band_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001350 "invalid",
1351 "AM",
1352 "FM mono",
1353 "TV NTSC-M",
1354 "FM stereo",
1355 "AUX",
1356 "TV PAL BG",
1357 "TV PAL I",
1358 "TV PAL DK",
1359 "TV SECAM",
1360};
1361
1362compile_time_assert(
1363 (ARRAY_SIZE(asihpi_tuner_band_names) ==
1364 (HPI_TUNER_BAND_LAST+1)),
1365 assert_tuner_band_names_size);
1366
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001367static const char * const asihpi_src_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001368 "no source",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001369 "PCM",
1370 "Line",
1371 "Digital",
1372 "Tuner",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001373 "RF",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001374 "Clock",
1375 "Bitstream",
1376 "Microphone",
1377 "Cobranet",
1378 "Analog",
1379 "Adapter",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001380};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001381
1382compile_time_assert(
1383 (ARRAY_SIZE(asihpi_src_names) ==
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12001384 (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001385 assert_src_names_size);
1386
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001387static const char * const asihpi_dst_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001388 "no destination",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001389 "PCM",
1390 "Line",
1391 "Digital",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001392 "RF",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001393 "Speaker",
1394 "Cobranet Out",
1395 "Analog"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001396};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001397
1398compile_time_assert(
1399 (ARRAY_SIZE(asihpi_dst_names) ==
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12001400 (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001401 assert_dst_names_size);
1402
1403static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
1404 struct snd_card_asihpi *asihpi)
1405{
1406 int err;
1407
1408 err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi));
1409 if (err < 0)
1410 return err;
1411 else if (mixer_dump)
1412 snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index);
1413
1414 return 0;
1415}
1416
1417/* Convert HPI control name and location into ALSA control name */
1418static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
1419 struct hpi_control *hpi_ctl,
1420 char *name)
1421{
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001422 char *dir = "";
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001423 memset(snd_control, 0, sizeof(*snd_control));
1424 snd_control->name = hpi_ctl->name;
1425 snd_control->private_value = hpi_ctl->h_control;
1426 snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1427 snd_control->index = 0;
1428
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001429 if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
1430 dir = "Capture "; /* On or towards a PCM capture destination*/
1431 else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1432 (!hpi_ctl->dst_node_type))
1433 dir = "Capture "; /* On a source node that is not PCM playback */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001434 else if (hpi_ctl->src_node_type &&
1435 (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001436 (hpi_ctl->dst_node_type))
1437 dir = "Monitor Playback "; /* Between an input and an output */
1438 else
1439 dir = "Playback "; /* PCM Playback source, or output node */
1440
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001441 if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001442 sprintf(hpi_ctl->name, "%s%d %s%d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001443 asihpi_src_names[hpi_ctl->src_node_type],
1444 hpi_ctl->src_node_index,
1445 asihpi_dst_names[hpi_ctl->dst_node_type],
1446 hpi_ctl->dst_node_index,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001447 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001448 else if (hpi_ctl->dst_node_type) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001449 sprintf(hpi_ctl->name, "%s %d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001450 asihpi_dst_names[hpi_ctl->dst_node_type],
1451 hpi_ctl->dst_node_index,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001452 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001453 } else {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001454 sprintf(hpi_ctl->name, "%s %d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001455 asihpi_src_names[hpi_ctl->src_node_type],
1456 hpi_ctl->src_node_index,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001457 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001458 }
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001459 /* printk(KERN_INFO "Adding %s %d to %d ", hpi_ctl->name,
1460 hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001461}
1462
1463/*------------------------------------------------------------
1464 Volume controls
1465 ------------------------------------------------------------*/
1466#define VOL_STEP_mB 1
1467static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
1468 struct snd_ctl_elem_info *uinfo)
1469{
1470 u32 h_control = kcontrol->private_value;
1471 u16 err;
1472 /* native gains are in millibels */
1473 short min_gain_mB;
1474 short max_gain_mB;
1475 short step_gain_mB;
1476
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001477 err = hpi_volume_query_range(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001478 &min_gain_mB, &max_gain_mB, &step_gain_mB);
1479 if (err) {
1480 max_gain_mB = 0;
1481 min_gain_mB = -10000;
1482 step_gain_mB = VOL_STEP_mB;
1483 }
1484
1485 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1486 uinfo->count = 2;
1487 uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;
1488 uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;
1489 uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;
1490 return 0;
1491}
1492
1493static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
1494 struct snd_ctl_elem_value *ucontrol)
1495{
1496 u32 h_control = kcontrol->private_value;
1497 short an_gain_mB[HPI_MAX_CHANNELS];
1498
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001499 hpi_handle_error(hpi_volume_get_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001500 ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;
1501 ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;
1502
1503 return 0;
1504}
1505
1506static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
1507 struct snd_ctl_elem_value *ucontrol)
1508{
1509 int change;
1510 u32 h_control = kcontrol->private_value;
1511 short an_gain_mB[HPI_MAX_CHANNELS];
1512
1513 an_gain_mB[0] =
1514 (ucontrol->value.integer.value[0]) * VOL_STEP_mB;
1515 an_gain_mB[1] =
1516 (ucontrol->value.integer.value[1]) * VOL_STEP_mB;
1517 /* change = asihpi->mixer_volume[addr][0] != left ||
1518 asihpi->mixer_volume[addr][1] != right;
1519 */
1520 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001521 hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001522 return change;
1523}
1524
1525static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
1526
1527static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
1528 struct hpi_control *hpi_ctl)
1529{
1530 struct snd_card *card = asihpi->card;
1531 struct snd_kcontrol_new snd_control;
1532
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001533 asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001534 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1535 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1536 snd_control.info = snd_asihpi_volume_info;
1537 snd_control.get = snd_asihpi_volume_get;
1538 snd_control.put = snd_asihpi_volume_put;
1539 snd_control.tlv.p = db_scale_100;
1540
1541 return ctl_add(card, &snd_control, asihpi);
1542}
1543
1544/*------------------------------------------------------------
1545 Level controls
1546 ------------------------------------------------------------*/
1547static int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,
1548 struct snd_ctl_elem_info *uinfo)
1549{
1550 u32 h_control = kcontrol->private_value;
1551 u16 err;
1552 short min_gain_mB;
1553 short max_gain_mB;
1554 short step_gain_mB;
1555
1556 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001557 hpi_level_query_range(h_control, &min_gain_mB,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001558 &max_gain_mB, &step_gain_mB);
1559 if (err) {
1560 max_gain_mB = 2400;
1561 min_gain_mB = -1000;
1562 step_gain_mB = 100;
1563 }
1564
1565 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1566 uinfo->count = 2;
1567 uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB;
1568 uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB;
1569 uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB;
1570 return 0;
1571}
1572
1573static int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,
1574 struct snd_ctl_elem_value *ucontrol)
1575{
1576 u32 h_control = kcontrol->private_value;
1577 short an_gain_mB[HPI_MAX_CHANNELS];
1578
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001579 hpi_handle_error(hpi_level_get_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001580 ucontrol->value.integer.value[0] =
1581 an_gain_mB[0] / HPI_UNITS_PER_dB;
1582 ucontrol->value.integer.value[1] =
1583 an_gain_mB[1] / HPI_UNITS_PER_dB;
1584
1585 return 0;
1586}
1587
1588static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,
1589 struct snd_ctl_elem_value *ucontrol)
1590{
1591 int change;
1592 u32 h_control = kcontrol->private_value;
1593 short an_gain_mB[HPI_MAX_CHANNELS];
1594
1595 an_gain_mB[0] =
1596 (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1597 an_gain_mB[1] =
1598 (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB;
1599 /* change = asihpi->mixer_level[addr][0] != left ||
1600 asihpi->mixer_level[addr][1] != right;
1601 */
1602 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001603 hpi_handle_error(hpi_level_set_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001604 return change;
1605}
1606
1607static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0);
1608
1609static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
1610 struct hpi_control *hpi_ctl)
1611{
1612 struct snd_card *card = asihpi->card;
1613 struct snd_kcontrol_new snd_control;
1614
1615 /* can't use 'volume' cos some nodes have volume as well */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001616 asihpi_ctl_init(&snd_control, hpi_ctl, "Level");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001617 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1618 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1619 snd_control.info = snd_asihpi_level_info;
1620 snd_control.get = snd_asihpi_level_get;
1621 snd_control.put = snd_asihpi_level_put;
1622 snd_control.tlv.p = db_scale_level;
1623
1624 return ctl_add(card, &snd_control, asihpi);
1625}
1626
1627/*------------------------------------------------------------
1628 AESEBU controls
1629 ------------------------------------------------------------*/
1630
1631/* AESEBU format */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001632static const char * const asihpi_aesebu_format_names[] = {
1633 "N/A", "S/PDIF", "AES/EBU" };
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001634
1635static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
1636 struct snd_ctl_elem_info *uinfo)
1637{
1638 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1639 uinfo->count = 1;
1640 uinfo->value.enumerated.items = 3;
1641
1642 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1643 uinfo->value.enumerated.item =
1644 uinfo->value.enumerated.items - 1;
1645
1646 strcpy(uinfo->value.enumerated.name,
1647 asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
1648
1649 return 0;
1650}
1651
1652static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
1653 struct snd_ctl_elem_value *ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001654 u16 (*func)(u32, u16 *))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001655{
1656 u32 h_control = kcontrol->private_value;
1657 u16 source, err;
1658
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001659 err = func(h_control, &source);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001660
1661 /* default to N/A */
1662 ucontrol->value.enumerated.item[0] = 0;
1663 /* return success but set the control to N/A */
1664 if (err)
1665 return 0;
1666 if (source == HPI_AESEBU_FORMAT_SPDIF)
1667 ucontrol->value.enumerated.item[0] = 1;
1668 if (source == HPI_AESEBU_FORMAT_AESEBU)
1669 ucontrol->value.enumerated.item[0] = 2;
1670
1671 return 0;
1672}
1673
1674static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
1675 struct snd_ctl_elem_value *ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001676 u16 (*func)(u32, u16))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001677{
1678 u32 h_control = kcontrol->private_value;
1679
1680 /* default to S/PDIF */
1681 u16 source = HPI_AESEBU_FORMAT_SPDIF;
1682
1683 if (ucontrol->value.enumerated.item[0] == 1)
1684 source = HPI_AESEBU_FORMAT_SPDIF;
1685 if (ucontrol->value.enumerated.item[0] == 2)
1686 source = HPI_AESEBU_FORMAT_AESEBU;
1687
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001688 if (func(h_control, source) != 0)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001689 return -EINVAL;
1690
1691 return 1;
1692}
1693
1694static int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,
1695 struct snd_ctl_elem_value *ucontrol) {
1696 return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001697 hpi_aesebu_receiver_get_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001698}
1699
1700static int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,
1701 struct snd_ctl_elem_value *ucontrol) {
1702 return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001703 hpi_aesebu_receiver_set_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001704}
1705
1706static int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol,
1707 struct snd_ctl_elem_info *uinfo)
1708{
1709 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1710 uinfo->count = 1;
1711
1712 uinfo->value.integer.min = 0;
1713 uinfo->value.integer.max = 0X1F;
1714 uinfo->value.integer.step = 1;
1715
1716 return 0;
1717}
1718
1719static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,
1720 struct snd_ctl_elem_value *ucontrol) {
1721
1722 u32 h_control = kcontrol->private_value;
1723 u16 status;
1724
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001725 hpi_handle_error(hpi_aesebu_receiver_get_error_status(
1726 h_control, &status));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001727 ucontrol->value.integer.value[0] = status;
1728 return 0;
1729}
1730
1731static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
1732 struct hpi_control *hpi_ctl)
1733{
1734 struct snd_card *card = asihpi->card;
1735 struct snd_kcontrol_new snd_control;
1736
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001737 asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001738 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1739 snd_control.info = snd_asihpi_aesebu_format_info;
1740 snd_control.get = snd_asihpi_aesebu_rx_format_get;
1741 snd_control.put = snd_asihpi_aesebu_rx_format_put;
1742
1743
1744 if (ctl_add(card, &snd_control, asihpi) < 0)
1745 return -EINVAL;
1746
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001747 asihpi_ctl_init(&snd_control, hpi_ctl, "Status");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001748 snd_control.access =
1749 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
1750 snd_control.info = snd_asihpi_aesebu_rxstatus_info;
1751 snd_control.get = snd_asihpi_aesebu_rxstatus_get;
1752
1753 return ctl_add(card, &snd_control, asihpi);
1754}
1755
1756static int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,
1757 struct snd_ctl_elem_value *ucontrol) {
1758 return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001759 hpi_aesebu_transmitter_get_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001760}
1761
1762static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,
1763 struct snd_ctl_elem_value *ucontrol) {
1764 return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001765 hpi_aesebu_transmitter_set_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001766}
1767
1768
1769static int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,
1770 struct hpi_control *hpi_ctl)
1771{
1772 struct snd_card *card = asihpi->card;
1773 struct snd_kcontrol_new snd_control;
1774
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001775 asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001776 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1777 snd_control.info = snd_asihpi_aesebu_format_info;
1778 snd_control.get = snd_asihpi_aesebu_tx_format_get;
1779 snd_control.put = snd_asihpi_aesebu_tx_format_put;
1780
1781 return ctl_add(card, &snd_control, asihpi);
1782}
1783
1784/*------------------------------------------------------------
1785 Tuner controls
1786 ------------------------------------------------------------*/
1787
1788/* Gain */
1789
1790static int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,
1791 struct snd_ctl_elem_info *uinfo)
1792{
1793 u32 h_control = kcontrol->private_value;
1794 u16 err;
1795 short idx;
1796 u16 gain_range[3];
1797
1798 for (idx = 0; idx < 3; idx++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001799 err = hpi_tuner_query_gain(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001800 idx, &gain_range[idx]);
1801 if (err != 0)
1802 return err;
1803 }
1804
1805 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1806 uinfo->count = 1;
1807 uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB;
1808 uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB;
1809 uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB;
1810 return 0;
1811}
1812
1813static int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,
1814 struct snd_ctl_elem_value *ucontrol)
1815{
1816 /*
1817 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1818 */
1819 u32 h_control = kcontrol->private_value;
1820 short gain;
1821
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001822 hpi_handle_error(hpi_tuner_get_gain(h_control, &gain));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001823 ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
1824
1825 return 0;
1826}
1827
1828static int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,
1829 struct snd_ctl_elem_value *ucontrol)
1830{
1831 /*
1832 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1833 */
1834 u32 h_control = kcontrol->private_value;
1835 short gain;
1836
1837 gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001838 hpi_handle_error(hpi_tuner_set_gain(h_control, gain));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001839
1840 return 1;
1841}
1842
1843/* Band */
1844
1845static int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,
1846 u16 *band_list, u32 len) {
1847 u32 h_control = kcontrol->private_value;
1848 u16 err = 0;
1849 u32 i;
1850
1851 for (i = 0; i < len; i++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001852 err = hpi_tuner_query_band(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001853 h_control, i, &band_list[i]);
1854 if (err != 0)
1855 break;
1856 }
1857
1858 if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX))
1859 return -EIO;
1860
1861 return i;
1862}
1863
1864static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
1865 struct snd_ctl_elem_info *uinfo)
1866{
1867 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1868 int num_bands = 0;
1869
1870 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1871 HPI_TUNER_BAND_LAST);
1872
1873 if (num_bands < 0)
1874 return num_bands;
1875
1876 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1877 uinfo->count = 1;
1878 uinfo->value.enumerated.items = num_bands;
1879
1880 if (num_bands > 0) {
1881 if (uinfo->value.enumerated.item >=
1882 uinfo->value.enumerated.items)
1883 uinfo->value.enumerated.item =
1884 uinfo->value.enumerated.items - 1;
1885
1886 strcpy(uinfo->value.enumerated.name,
1887 asihpi_tuner_band_names[
1888 tuner_bands[uinfo->value.enumerated.item]]);
1889
1890 }
1891 return 0;
1892}
1893
1894static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
1895 struct snd_ctl_elem_value *ucontrol)
1896{
1897 u32 h_control = kcontrol->private_value;
1898 /*
1899 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1900 */
1901 u16 band, idx;
1902 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1903 u32 num_bands = 0;
1904
1905 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1906 HPI_TUNER_BAND_LAST);
1907
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001908 hpi_handle_error(hpi_tuner_get_band(h_control, &band));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001909
1910 ucontrol->value.enumerated.item[0] = -1;
1911 for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
1912 if (tuner_bands[idx] == band) {
1913 ucontrol->value.enumerated.item[0] = idx;
1914 break;
1915 }
1916
1917 return 0;
1918}
1919
1920static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
1921 struct snd_ctl_elem_value *ucontrol)
1922{
1923 /*
1924 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1925 */
1926 u32 h_control = kcontrol->private_value;
1927 u16 band;
1928 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1929 u32 num_bands = 0;
1930
1931 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1932 HPI_TUNER_BAND_LAST);
1933
1934 band = tuner_bands[ucontrol->value.enumerated.item[0]];
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001935 hpi_handle_error(hpi_tuner_set_band(h_control, band));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001936
1937 return 1;
1938}
1939
1940/* Freq */
1941
1942static int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,
1943 struct snd_ctl_elem_info *uinfo)
1944{
1945 u32 h_control = kcontrol->private_value;
1946 u16 err;
1947 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1948 u16 num_bands = 0, band_iter, idx;
1949 u32 freq_range[3], temp_freq_range[3];
1950
1951 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1952 HPI_TUNER_BAND_LAST);
1953
1954 freq_range[0] = INT_MAX;
1955 freq_range[1] = 0;
1956 freq_range[2] = INT_MAX;
1957
1958 for (band_iter = 0; band_iter < num_bands; band_iter++) {
1959 for (idx = 0; idx < 3; idx++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001960 err = hpi_tuner_query_frequency(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001961 idx, tuner_bands[band_iter],
1962 &temp_freq_range[idx]);
1963 if (err != 0)
1964 return err;
1965 }
1966
1967 /* skip band with bogus stepping */
1968 if (temp_freq_range[2] <= 0)
1969 continue;
1970
1971 if (temp_freq_range[0] < freq_range[0])
1972 freq_range[0] = temp_freq_range[0];
1973 if (temp_freq_range[1] > freq_range[1])
1974 freq_range[1] = temp_freq_range[1];
1975 if (temp_freq_range[2] < freq_range[2])
1976 freq_range[2] = temp_freq_range[2];
1977 }
1978
1979 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1980 uinfo->count = 1;
1981 uinfo->value.integer.min = ((int)freq_range[0]);
1982 uinfo->value.integer.max = ((int)freq_range[1]);
1983 uinfo->value.integer.step = ((int)freq_range[2]);
1984 return 0;
1985}
1986
1987static int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,
1988 struct snd_ctl_elem_value *ucontrol)
1989{
1990 u32 h_control = kcontrol->private_value;
1991 u32 freq;
1992
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001993 hpi_handle_error(hpi_tuner_get_frequency(h_control, &freq));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001994 ucontrol->value.integer.value[0] = freq;
1995
1996 return 0;
1997}
1998
1999static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,
2000 struct snd_ctl_elem_value *ucontrol)
2001{
2002 u32 h_control = kcontrol->private_value;
2003 u32 freq;
2004
2005 freq = ucontrol->value.integer.value[0];
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002006 hpi_handle_error(hpi_tuner_set_frequency(h_control, freq));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002007
2008 return 1;
2009}
2010
2011/* Tuner control group initializer */
2012static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
2013 struct hpi_control *hpi_ctl)
2014{
2015 struct snd_card *card = asihpi->card;
2016 struct snd_kcontrol_new snd_control;
2017
2018 snd_control.private_value = hpi_ctl->h_control;
2019 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2020
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002021 if (!hpi_tuner_get_gain(hpi_ctl->h_control, NULL)) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002022 asihpi_ctl_init(&snd_control, hpi_ctl, "Gain");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002023 snd_control.info = snd_asihpi_tuner_gain_info;
2024 snd_control.get = snd_asihpi_tuner_gain_get;
2025 snd_control.put = snd_asihpi_tuner_gain_put;
2026
2027 if (ctl_add(card, &snd_control, asihpi) < 0)
2028 return -EINVAL;
2029 }
2030
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002031 asihpi_ctl_init(&snd_control, hpi_ctl, "Band");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002032 snd_control.info = snd_asihpi_tuner_band_info;
2033 snd_control.get = snd_asihpi_tuner_band_get;
2034 snd_control.put = snd_asihpi_tuner_band_put;
2035
2036 if (ctl_add(card, &snd_control, asihpi) < 0)
2037 return -EINVAL;
2038
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002039 asihpi_ctl_init(&snd_control, hpi_ctl, "Freq");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002040 snd_control.info = snd_asihpi_tuner_freq_info;
2041 snd_control.get = snd_asihpi_tuner_freq_get;
2042 snd_control.put = snd_asihpi_tuner_freq_put;
2043
2044 return ctl_add(card, &snd_control, asihpi);
2045}
2046
2047/*------------------------------------------------------------
2048 Meter controls
2049 ------------------------------------------------------------*/
2050static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,
2051 struct snd_ctl_elem_info *uinfo)
2052{
2053 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2054 uinfo->count = HPI_MAX_CHANNELS;
2055 uinfo->value.integer.min = 0;
2056 uinfo->value.integer.max = 0x7FFFFFFF;
2057 return 0;
2058}
2059
2060/* linear values for 10dB steps */
2061static int log2lin[] = {
2062 0x7FFFFFFF, /* 0dB */
2063 679093956,
2064 214748365,
2065 67909396,
2066 21474837,
2067 6790940,
2068 2147484, /* -60dB */
2069 679094,
2070 214748, /* -80 */
2071 67909,
2072 21475, /* -100 */
2073 6791,
2074 2147,
2075 679,
2076 214,
2077 68,
2078 21,
2079 7,
2080 2
2081};
2082
2083static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,
2084 struct snd_ctl_elem_value *ucontrol)
2085{
2086 u32 h_control = kcontrol->private_value;
2087 short an_gain_mB[HPI_MAX_CHANNELS], i;
2088 u16 err;
2089
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002090 err = hpi_meter_get_peak(h_control, an_gain_mB);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002091
2092 for (i = 0; i < HPI_MAX_CHANNELS; i++) {
2093 if (err) {
2094 ucontrol->value.integer.value[i] = 0;
2095 } else if (an_gain_mB[i] >= 0) {
2096 ucontrol->value.integer.value[i] =
2097 an_gain_mB[i] << 16;
2098 } else {
2099 /* -ve is log value in millibels < -60dB,
2100 * convert to (roughly!) linear,
2101 */
2102 ucontrol->value.integer.value[i] =
2103 log2lin[an_gain_mB[i] / -1000];
2104 }
2105 }
2106 return 0;
2107}
2108
2109static int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,
2110 struct hpi_control *hpi_ctl, int subidx)
2111{
2112 struct snd_card *card = asihpi->card;
2113 struct snd_kcontrol_new snd_control;
2114
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002115 asihpi_ctl_init(&snd_control, hpi_ctl, "Meter");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002116 snd_control.access =
2117 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2118 snd_control.info = snd_asihpi_meter_info;
2119 snd_control.get = snd_asihpi_meter_get;
2120
2121 snd_control.index = subidx;
2122
2123 return ctl_add(card, &snd_control, asihpi);
2124}
2125
2126/*------------------------------------------------------------
2127 Multiplexer controls
2128 ------------------------------------------------------------*/
2129static int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)
2130{
2131 u32 h_control = snd_control->private_value;
2132 struct hpi_control hpi_ctl;
2133 int s, err;
2134 for (s = 0; s < 32; s++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002135 err = hpi_multiplexer_query_source(h_control, s,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002136 &hpi_ctl.
2137 src_node_type,
2138 &hpi_ctl.
2139 src_node_index);
2140 if (err)
2141 break;
2142 }
2143 return s;
2144}
2145
2146static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
2147 struct snd_ctl_elem_info *uinfo)
2148{
2149 int err;
2150 u16 src_node_type, src_node_index;
2151 u32 h_control = kcontrol->private_value;
2152
2153 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2154 uinfo->count = 1;
2155 uinfo->value.enumerated.items =
2156 snd_card_asihpi_mux_count_sources(kcontrol);
2157
2158 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2159 uinfo->value.enumerated.item =
2160 uinfo->value.enumerated.items - 1;
2161
2162 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002163 hpi_multiplexer_query_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002164 uinfo->value.enumerated.item,
2165 &src_node_type, &src_node_index);
2166
2167 sprintf(uinfo->value.enumerated.name, "%s %d",
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12002168 asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002169 src_node_index);
2170 return 0;
2171}
2172
2173static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
2174 struct snd_ctl_elem_value *ucontrol)
2175{
2176 u32 h_control = kcontrol->private_value;
2177 u16 source_type, source_index;
2178 u16 src_node_type, src_node_index;
2179 int s;
2180
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002181 hpi_handle_error(hpi_multiplexer_get_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002182 &source_type, &source_index));
2183 /* Should cache this search result! */
2184 for (s = 0; s < 256; s++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002185 if (hpi_multiplexer_query_source(h_control, s,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002186 &src_node_type, &src_node_index))
2187 break;
2188
2189 if ((source_type == src_node_type)
2190 && (source_index == src_node_index)) {
2191 ucontrol->value.enumerated.item[0] = s;
2192 return 0;
2193 }
2194 }
2195 snd_printd(KERN_WARNING
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002196 "Control %x failed to match mux source %hu %hu\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002197 h_control, source_type, source_index);
2198 ucontrol->value.enumerated.item[0] = 0;
2199 return 0;
2200}
2201
2202static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,
2203 struct snd_ctl_elem_value *ucontrol)
2204{
2205 int change;
2206 u32 h_control = kcontrol->private_value;
2207 u16 source_type, source_index;
2208 u16 e;
2209
2210 change = 1;
2211
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002212 e = hpi_multiplexer_query_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002213 ucontrol->value.enumerated.item[0],
2214 &source_type, &source_index);
2215 if (!e)
2216 hpi_handle_error(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002217 hpi_multiplexer_set_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002218 source_type, source_index));
2219 return change;
2220}
2221
2222
2223static int __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
2224 struct hpi_control *hpi_ctl)
2225{
2226 struct snd_card *card = asihpi->card;
2227 struct snd_kcontrol_new snd_control;
2228
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002229 asihpi_ctl_init(&snd_control, hpi_ctl, "Route");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002230 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2231 snd_control.info = snd_asihpi_mux_info;
2232 snd_control.get = snd_asihpi_mux_get;
2233 snd_control.put = snd_asihpi_mux_put;
2234
2235 return ctl_add(card, &snd_control, asihpi);
2236
2237}
2238
2239/*------------------------------------------------------------
2240 Channel mode controls
2241 ------------------------------------------------------------*/
2242static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
2243 struct snd_ctl_elem_info *uinfo)
2244{
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002245 static const char * const mode_names[HPI_CHANNEL_MODE_LAST + 1] = {
2246 "invalid",
2247 "Normal", "Swap",
2248 "From Left", "From Right",
2249 "To Left", "To Right"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002250 };
2251
2252 u32 h_control = kcontrol->private_value;
2253 u16 mode;
2254 int i;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002255 u16 mode_map[6];
2256 int valid_modes = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002257
2258 /* HPI channel mode values can be from 1 to 6
2259 Some adapters only support a contiguous subset
2260 */
2261 for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002262 if (!hpi_channel_mode_query_mode(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002263 h_control, i, &mode)) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002264 mode_map[valid_modes] = mode;
2265 valid_modes++;
2266 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002267
2268 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2269 uinfo->count = 1;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002270 uinfo->value.enumerated.items = valid_modes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002271
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002272 if (uinfo->value.enumerated.item >= valid_modes)
2273 uinfo->value.enumerated.item = valid_modes - 1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002274
2275 strcpy(uinfo->value.enumerated.name,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002276 mode_names[mode_map[uinfo->value.enumerated.item]]);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002277
2278 return 0;
2279}
2280
2281static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
2282 struct snd_ctl_elem_value *ucontrol)
2283{
2284 u32 h_control = kcontrol->private_value;
2285 u16 mode;
2286
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002287 if (hpi_channel_mode_get(h_control, &mode))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002288 mode = 1;
2289
2290 ucontrol->value.enumerated.item[0] = mode - 1;
2291
2292 return 0;
2293}
2294
2295static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,
2296 struct snd_ctl_elem_value *ucontrol)
2297{
2298 int change;
2299 u32 h_control = kcontrol->private_value;
2300
2301 change = 1;
2302
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002303 hpi_handle_error(hpi_channel_mode_set(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002304 ucontrol->value.enumerated.item[0] + 1));
2305 return change;
2306}
2307
2308
2309static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
2310 struct hpi_control *hpi_ctl)
2311{
2312 struct snd_card *card = asihpi->card;
2313 struct snd_kcontrol_new snd_control;
2314
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002315 asihpi_ctl_init(&snd_control, hpi_ctl, "Mode");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002316 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2317 snd_control.info = snd_asihpi_cmode_info;
2318 snd_control.get = snd_asihpi_cmode_get;
2319 snd_control.put = snd_asihpi_cmode_put;
2320
2321 return ctl_add(card, &snd_control, asihpi);
2322}
2323
2324/*------------------------------------------------------------
2325 Sampleclock source controls
2326 ------------------------------------------------------------*/
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002327static char *sampleclock_sources[MAX_CLOCKSOURCES] = {
2328 "N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
2329 "SMPTE", "Digital1", "Auto", "Network", "Invalid",
2330 "Prev Module",
2331 "Digital2", "Digital3", "Digital4", "Digital5",
2332 "Digital6", "Digital7", "Digital8"};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002333
2334static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
2335 struct snd_ctl_elem_info *uinfo)
2336{
2337 struct snd_card_asihpi *asihpi =
2338 (struct snd_card_asihpi *)(kcontrol->private_data);
2339 struct clk_cache *clkcache = &asihpi->cc;
2340 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2341 uinfo->count = 1;
2342 uinfo->value.enumerated.items = clkcache->count;
2343
2344 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2345 uinfo->value.enumerated.item =
2346 uinfo->value.enumerated.items - 1;
2347
2348 strcpy(uinfo->value.enumerated.name,
2349 clkcache->s[uinfo->value.enumerated.item].name);
2350 return 0;
2351}
2352
2353static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
2354 struct snd_ctl_elem_value *ucontrol)
2355{
2356 struct snd_card_asihpi *asihpi =
2357 (struct snd_card_asihpi *)(kcontrol->private_data);
2358 struct clk_cache *clkcache = &asihpi->cc;
2359 u32 h_control = kcontrol->private_value;
2360 u16 source, srcindex = 0;
2361 int i;
2362
2363 ucontrol->value.enumerated.item[0] = 0;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002364 if (hpi_sample_clock_get_source(h_control, &source))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002365 source = 0;
2366
2367 if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002368 if (hpi_sample_clock_get_source_index(h_control, &srcindex))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002369 srcindex = 0;
2370
2371 for (i = 0; i < clkcache->count; i++)
2372 if ((clkcache->s[i].source == source) &&
2373 (clkcache->s[i].index == srcindex))
2374 break;
2375
2376 ucontrol->value.enumerated.item[0] = i;
2377
2378 return 0;
2379}
2380
2381static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
2382 struct snd_ctl_elem_value *ucontrol)
2383{
2384 struct snd_card_asihpi *asihpi =
2385 (struct snd_card_asihpi *)(kcontrol->private_data);
2386 struct clk_cache *clkcache = &asihpi->cc;
2387 int change, item;
2388 u32 h_control = kcontrol->private_value;
2389
2390 change = 1;
2391 item = ucontrol->value.enumerated.item[0];
2392 if (item >= clkcache->count)
2393 item = clkcache->count-1;
2394
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002395 hpi_handle_error(hpi_sample_clock_set_source(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002396 h_control, clkcache->s[item].source));
2397
2398 if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002399 hpi_handle_error(hpi_sample_clock_set_source_index(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002400 h_control, clkcache->s[item].index));
2401 return change;
2402}
2403
2404/*------------------------------------------------------------
2405 Clkrate controls
2406 ------------------------------------------------------------*/
2407/* Need to change this to enumerated control with list of rates */
2408static int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol,
2409 struct snd_ctl_elem_info *uinfo)
2410{
2411 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2412 uinfo->count = 1;
2413 uinfo->value.integer.min = 8000;
2414 uinfo->value.integer.max = 192000;
2415 uinfo->value.integer.step = 100;
2416
2417 return 0;
2418}
2419
2420static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,
2421 struct snd_ctl_elem_value *ucontrol)
2422{
2423 u32 h_control = kcontrol->private_value;
2424 u32 rate;
2425 u16 e;
2426
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002427 e = hpi_sample_clock_get_local_rate(h_control, &rate);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002428 if (!e)
2429 ucontrol->value.integer.value[0] = rate;
2430 else
2431 ucontrol->value.integer.value[0] = 0;
2432 return 0;
2433}
2434
2435static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,
2436 struct snd_ctl_elem_value *ucontrol)
2437{
2438 int change;
2439 u32 h_control = kcontrol->private_value;
2440
2441 /* change = asihpi->mixer_clkrate[addr][0] != left ||
2442 asihpi->mixer_clkrate[addr][1] != right;
2443 */
2444 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002445 hpi_handle_error(hpi_sample_clock_set_local_rate(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002446 ucontrol->value.integer.value[0]));
2447 return change;
2448}
2449
2450static int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol,
2451 struct snd_ctl_elem_info *uinfo)
2452{
2453 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2454 uinfo->count = 1;
2455 uinfo->value.integer.min = 8000;
2456 uinfo->value.integer.max = 192000;
2457 uinfo->value.integer.step = 100;
2458
2459 return 0;
2460}
2461
2462static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
2463 struct snd_ctl_elem_value *ucontrol)
2464{
2465 u32 h_control = kcontrol->private_value;
2466 u32 rate;
2467 u16 e;
2468
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002469 e = hpi_sample_clock_get_sample_rate(h_control, &rate);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002470 if (!e)
2471 ucontrol->value.integer.value[0] = rate;
2472 else
2473 ucontrol->value.integer.value[0] = 0;
2474 return 0;
2475}
2476
2477static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
2478 struct hpi_control *hpi_ctl)
2479{
2480 struct snd_card *card = asihpi->card;
2481 struct snd_kcontrol_new snd_control;
2482
2483 struct clk_cache *clkcache = &asihpi->cc;
2484 u32 hSC = hpi_ctl->h_control;
2485 int has_aes_in = 0;
2486 int i, j;
2487 u16 source;
2488
2489 snd_control.private_value = hpi_ctl->h_control;
2490
2491 clkcache->has_local = 0;
2492
2493 for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002494 if (hpi_sample_clock_query_source(hSC,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002495 i, &source))
2496 break;
2497 clkcache->s[i].source = source;
2498 clkcache->s[i].index = 0;
2499 clkcache->s[i].name = sampleclock_sources[source];
2500 if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2501 has_aes_in = 1;
2502 if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL)
2503 clkcache->has_local = 1;
2504 }
2505 if (has_aes_in)
2506 /* already will have picked up index 0 above */
2507 for (j = 1; j < 8; j++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002508 if (hpi_sample_clock_query_source_index(hSC,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002509 j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,
2510 &source))
2511 break;
2512 clkcache->s[i].source =
2513 HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT;
2514 clkcache->s[i].index = j;
2515 clkcache->s[i].name = sampleclock_sources[
2516 j+HPI_SAMPLECLOCK_SOURCE_LAST];
2517 i++;
2518 }
2519 clkcache->count = i;
2520
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002521 asihpi_ctl_init(&snd_control, hpi_ctl, "Source");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002522 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2523 snd_control.info = snd_asihpi_clksrc_info;
2524 snd_control.get = snd_asihpi_clksrc_get;
2525 snd_control.put = snd_asihpi_clksrc_put;
2526 if (ctl_add(card, &snd_control, asihpi) < 0)
2527 return -EINVAL;
2528
2529
2530 if (clkcache->has_local) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002531 asihpi_ctl_init(&snd_control, hpi_ctl, "Localrate");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002532 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2533 snd_control.info = snd_asihpi_clklocal_info;
2534 snd_control.get = snd_asihpi_clklocal_get;
2535 snd_control.put = snd_asihpi_clklocal_put;
2536
2537
2538 if (ctl_add(card, &snd_control, asihpi) < 0)
2539 return -EINVAL;
2540 }
2541
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002542 asihpi_ctl_init(&snd_control, hpi_ctl, "Rate");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002543 snd_control.access =
2544 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2545 snd_control.info = snd_asihpi_clkrate_info;
2546 snd_control.get = snd_asihpi_clkrate_get;
2547
2548 return ctl_add(card, &snd_control, asihpi);
2549}
2550/*------------------------------------------------------------
2551 Mixer
2552 ------------------------------------------------------------*/
2553
2554static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
2555{
2556 struct snd_card *card = asihpi->card;
2557 unsigned int idx = 0;
2558 unsigned int subindex = 0;
2559 int err;
2560 struct hpi_control hpi_ctl, prev_ctl;
2561
2562 if (snd_BUG_ON(!asihpi))
2563 return -EINVAL;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002564 strcpy(card->mixername, "Asihpi Mixer");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002565
2566 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002567 hpi_mixer_open(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002568 &asihpi->h_mixer);
2569 hpi_handle_error(err);
2570 if (err)
2571 return -err;
2572
Takashi Iwai21896bc2010-06-02 12:08:37 +02002573 memset(&prev_ctl, 0, sizeof(prev_ctl));
2574 prev_ctl.control_type = -1;
2575
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002576 for (idx = 0; idx < 2000; idx++) {
2577 err = hpi_mixer_get_control_by_index(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002578 asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002579 idx,
2580 &hpi_ctl.src_node_type,
2581 &hpi_ctl.src_node_index,
2582 &hpi_ctl.dst_node_type,
2583 &hpi_ctl.dst_node_index,
2584 &hpi_ctl.control_type,
2585 &hpi_ctl.h_control);
2586 if (err) {
2587 if (err == HPI_ERROR_CONTROL_DISABLED) {
2588 if (mixer_dump)
2589 snd_printk(KERN_INFO
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002590 "Disabled HPI Control(%d)\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002591 idx);
2592 continue;
2593 } else
2594 break;
2595
2596 }
2597
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12002598 hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;
2599 hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002600
2601 /* ASI50xx in SSX mode has multiple meters on the same node.
2602 Use subindex to create distinct ALSA controls
2603 for any duplicated controls.
2604 */
2605 if ((hpi_ctl.control_type == prev_ctl.control_type) &&
2606 (hpi_ctl.src_node_type == prev_ctl.src_node_type) &&
2607 (hpi_ctl.src_node_index == prev_ctl.src_node_index) &&
2608 (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) &&
2609 (hpi_ctl.dst_node_index == prev_ctl.dst_node_index))
2610 subindex++;
2611 else
2612 subindex = 0;
2613
2614 prev_ctl = hpi_ctl;
2615
2616 switch (hpi_ctl.control_type) {
2617 case HPI_CONTROL_VOLUME:
2618 err = snd_asihpi_volume_add(asihpi, &hpi_ctl);
2619 break;
2620 case HPI_CONTROL_LEVEL:
2621 err = snd_asihpi_level_add(asihpi, &hpi_ctl);
2622 break;
2623 case HPI_CONTROL_MULTIPLEXER:
2624 err = snd_asihpi_mux_add(asihpi, &hpi_ctl);
2625 break;
2626 case HPI_CONTROL_CHANNEL_MODE:
2627 err = snd_asihpi_cmode_add(asihpi, &hpi_ctl);
2628 break;
2629 case HPI_CONTROL_METER:
2630 err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex);
2631 break;
2632 case HPI_CONTROL_SAMPLECLOCK:
2633 err = snd_asihpi_sampleclock_add(
2634 asihpi, &hpi_ctl);
2635 break;
2636 case HPI_CONTROL_CONNECTION: /* ignore these */
2637 continue;
2638 case HPI_CONTROL_TUNER:
2639 err = snd_asihpi_tuner_add(asihpi, &hpi_ctl);
2640 break;
2641 case HPI_CONTROL_AESEBU_TRANSMITTER:
2642 err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl);
2643 break;
2644 case HPI_CONTROL_AESEBU_RECEIVER:
2645 err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl);
2646 break;
2647 case HPI_CONTROL_VOX:
2648 case HPI_CONTROL_BITSTREAM:
2649 case HPI_CONTROL_MICROPHONE:
2650 case HPI_CONTROL_PARAMETRIC_EQ:
2651 case HPI_CONTROL_COMPANDER:
2652 default:
2653 if (mixer_dump)
2654 snd_printk(KERN_INFO
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002655 "Untranslated HPI Control"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002656 "(%d) %d %d %d %d %d\n",
2657 idx,
2658 hpi_ctl.control_type,
2659 hpi_ctl.src_node_type,
2660 hpi_ctl.src_node_index,
2661 hpi_ctl.dst_node_type,
2662 hpi_ctl.dst_node_index);
2663 continue;
2664 };
2665 if (err < 0)
2666 return err;
2667 }
2668 if (HPI_ERROR_INVALID_OBJ_INDEX != err)
2669 hpi_handle_error(err);
2670
2671 snd_printk(KERN_INFO "%d mixer controls found\n", idx);
2672
2673 return 0;
2674}
2675
2676/*------------------------------------------------------------
2677 /proc interface
2678 ------------------------------------------------------------*/
2679
2680static void
2681snd_asihpi_proc_read(struct snd_info_entry *entry,
2682 struct snd_info_buffer *buffer)
2683{
2684 struct snd_card_asihpi *asihpi = entry->private_data;
2685 u16 version;
2686 u32 h_control;
2687 u32 rate = 0;
2688 u16 source = 0;
2689 int err;
2690
2691 snd_iprintf(buffer, "ASIHPI driver proc file\n");
2692 snd_iprintf(buffer,
2693 "adapter ID=%4X\n_index=%d\n"
2694 "num_outstreams=%d\n_num_instreams=%d\n",
2695 asihpi->type, asihpi->adapter_index,
2696 asihpi->num_outstreams, asihpi->num_instreams);
2697
2698 version = asihpi->version;
2699 snd_iprintf(buffer,
2700 "serial#=%d\n_hw version %c%d\nDSP code version %03d\n",
2701 asihpi->serial_number, ((version >> 3) & 0xf) + 'A',
2702 version & 0x7,
2703 ((version >> 13) * 100) + ((version >> 7) & 0x3f));
2704
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002705 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002706 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2707 HPI_CONTROL_SAMPLECLOCK, &h_control);
2708
2709 if (!err) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002710 err = hpi_sample_clock_get_sample_rate(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002711 h_control, &rate);
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002712 err += hpi_sample_clock_get_source(h_control, &source);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002713
2714 if (!err)
2715 snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n",
2716 rate, sampleclock_sources[source]);
2717 }
2718
2719}
2720
2721
2722static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
2723{
2724 struct snd_info_entry *entry;
2725
2726 if (!snd_card_proc_new(asihpi->card, "info", &entry))
2727 snd_info_set_text_ops(entry, asihpi, snd_asihpi_proc_read);
2728}
2729
2730/*------------------------------------------------------------
2731 HWDEP
2732 ------------------------------------------------------------*/
2733
2734static int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file)
2735{
2736 if (enable_hpi_hwdep)
2737 return 0;
2738 else
2739 return -ENODEV;
2740
2741}
2742
2743static int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file)
2744{
2745 if (enable_hpi_hwdep)
2746 return asihpi_hpi_release(file);
2747 else
2748 return -ENODEV;
2749}
2750
2751static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
2752 unsigned int cmd, unsigned long arg)
2753{
2754 if (enable_hpi_hwdep)
2755 return asihpi_hpi_ioctl(file, cmd, arg);
2756 else
2757 return -ENODEV;
2758}
2759
2760
2761/* results in /dev/snd/hwC#D0 file for each card with index #
2762 also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
2763*/
2764static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
2765 int device, struct snd_hwdep **rhwdep)
2766{
2767 struct snd_hwdep *hw;
2768 int err;
2769
2770 if (rhwdep)
2771 *rhwdep = NULL;
2772 err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
2773 if (err < 0)
2774 return err;
2775 strcpy(hw->name, "asihpi (HPI)");
2776 hw->iface = SNDRV_HWDEP_IFACE_LAST;
2777 hw->ops.open = snd_asihpi_hpi_open;
2778 hw->ops.ioctl = snd_asihpi_hpi_ioctl;
2779 hw->ops.release = snd_asihpi_hpi_release;
2780 hw->private_data = asihpi;
2781 if (rhwdep)
2782 *rhwdep = hw;
2783 return 0;
2784}
2785
2786/*------------------------------------------------------------
2787 CARD
2788 ------------------------------------------------------------*/
2789static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
2790 const struct pci_device_id *pci_id)
2791{
2792 int err;
2793
2794 u16 version;
2795 int pcm_substreams;
2796
2797 struct hpi_adapter *hpi_card;
2798 struct snd_card *card;
2799 struct snd_card_asihpi *asihpi;
2800
2801 u32 h_control;
2802 u32 h_stream;
2803
2804 static int dev;
2805 if (dev >= SNDRV_CARDS)
2806 return -ENODEV;
2807
2808 /* Should this be enable[hpi_card->index] ? */
2809 if (!enable[dev]) {
2810 dev++;
2811 return -ENOENT;
2812 }
2813
2814 err = asihpi_adapter_probe(pci_dev, pci_id);
2815 if (err < 0)
2816 return err;
2817
2818 hpi_card = pci_get_drvdata(pci_dev);
2819 /* first try to give the card the same index as its hardware index */
2820 err = snd_card_create(hpi_card->index,
2821 id[hpi_card->index], THIS_MODULE,
2822 sizeof(struct snd_card_asihpi),
2823 &card);
2824 if (err < 0) {
2825 /* if that fails, try the default index==next available */
2826 err =
2827 snd_card_create(index[dev], id[dev],
2828 THIS_MODULE,
2829 sizeof(struct snd_card_asihpi),
2830 &card);
2831 if (err < 0)
2832 return err;
2833 snd_printk(KERN_WARNING
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002834 "**** WARNING **** Adapter index %d->ALSA index %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002835 hpi_card->index, card->number);
2836 }
2837
Eliot Blennerhassett12253672011-02-10 17:26:10 +13002838 snd_card_set_dev(card, &pci_dev->dev);
2839
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002840 asihpi = (struct snd_card_asihpi *) card->private_data;
2841 asihpi->card = card;
Eliot Blennerhassett12253672011-02-10 17:26:10 +13002842 asihpi->pci = pci_dev;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002843 asihpi->adapter_index = hpi_card->index;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002844 hpi_handle_error(hpi_adapter_get_info(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002845 asihpi->adapter_index,
2846 &asihpi->num_outstreams,
2847 &asihpi->num_instreams,
2848 &asihpi->version,
2849 &asihpi->serial_number, &asihpi->type));
2850
2851 version = asihpi->version;
2852 snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d "
2853 "num_instreams=%d S/N=%d\n"
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002854 "Hw Version %c%d DSP code version %03d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002855 asihpi->type, asihpi->adapter_index,
2856 asihpi->num_outstreams,
2857 asihpi->num_instreams, asihpi->serial_number,
2858 ((version >> 3) & 0xf) + 'A',
2859 version & 0x7,
2860 ((version >> 13) * 100) + ((version >> 7) & 0x3f));
2861
2862 pcm_substreams = asihpi->num_outstreams;
2863 if (pcm_substreams < asihpi->num_instreams)
2864 pcm_substreams = asihpi->num_instreams;
2865
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002866 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002867 HPI_ADAPTER_PROPERTY_CAPS1,
2868 NULL, &asihpi->support_grouping);
2869 if (err)
2870 asihpi->support_grouping = 0;
2871
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002872 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002873 HPI_ADAPTER_PROPERTY_CAPS2,
2874 &asihpi->support_mrx, NULL);
2875 if (err)
2876 asihpi->support_mrx = 0;
2877
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002878 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002879 HPI_ADAPTER_PROPERTY_INTERVAL,
2880 NULL, &asihpi->update_interval_frames);
2881 if (err)
2882 asihpi->update_interval_frames = 512;
2883
Eliot Blennerhassett26aebef2011-03-25 15:25:47 +13002884 if (!asihpi->support_mmap)
2885 asihpi->update_interval_frames *= 2;
2886
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002887 hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002888 0, &h_stream));
2889
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002890 err = hpi_instream_host_buffer_free(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002891 asihpi->support_mmap = (!err);
2892
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002893 hpi_handle_error(hpi_instream_close(h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002894
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002895 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002896 HPI_ADAPTER_PROPERTY_CURCHANNELS,
2897 &asihpi->in_max_chans, &asihpi->out_max_chans);
2898 if (err) {
2899 asihpi->in_max_chans = 2;
2900 asihpi->out_max_chans = 2;
2901 }
2902
2903 snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n",
2904 asihpi->support_mmap,
2905 asihpi->support_grouping,
2906 asihpi->support_mrx
2907 );
2908
2909
2910 err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams);
2911 if (err < 0) {
2912 snd_printk(KERN_ERR "pcm_new failed\n");
2913 goto __nodev;
2914 }
2915 err = snd_card_asihpi_mixer_new(asihpi);
2916 if (err < 0) {
2917 snd_printk(KERN_ERR "mixer_new failed\n");
2918 goto __nodev;
2919 }
2920
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002921 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002922 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2923 HPI_CONTROL_SAMPLECLOCK, &h_control);
2924
2925 if (!err)
2926 err = hpi_sample_clock_set_local_rate(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002927 h_control, adapter_fs);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002928
2929 snd_asihpi_proc_init(asihpi);
2930
2931 /* always create, can be enabled or disabled dynamically
2932 by enable_hwdep module param*/
2933 snd_asihpi_hpi_new(asihpi, 0, NULL);
2934
2935 if (asihpi->support_mmap)
2936 strcpy(card->driver, "ASIHPI-MMAP");
2937 else
2938 strcpy(card->driver, "ASIHPI");
2939
2940 sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
2941 sprintf(card->longname, "%s %i",
2942 card->shortname, asihpi->adapter_index);
2943 err = snd_card_register(card);
2944 if (!err) {
2945 hpi_card->snd_card_asihpi = card;
2946 dev++;
2947 return 0;
2948 }
2949__nodev:
2950 snd_card_free(card);
2951 snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err);
2952 return err;
2953
2954}
2955
2956static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev)
2957{
2958 struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev);
2959
2960 snd_card_free(hpi_card->snd_card_asihpi);
2961 hpi_card->snd_card_asihpi = NULL;
2962 asihpi_adapter_remove(pci_dev);
2963}
2964
2965static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = {
2966 {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
2967 HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2968 (kernel_ulong_t)HPI_6205},
2969 {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
2970 HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2971 (kernel_ulong_t)HPI_6000},
2972 {0,}
2973};
2974MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
2975
2976static struct pci_driver driver = {
2977 .name = "asihpi",
2978 .id_table = asihpi_pci_tbl,
2979 .probe = snd_asihpi_probe,
2980 .remove = __devexit_p(snd_asihpi_remove),
2981#ifdef CONFIG_PM
2982/* .suspend = snd_asihpi_suspend,
2983 .resume = snd_asihpi_resume, */
2984#endif
2985};
2986
2987static int __init snd_asihpi_init(void)
2988{
2989 asihpi_init();
2990 return pci_register_driver(&driver);
2991}
2992
2993static void __exit snd_asihpi_exit(void)
2994{
2995
2996 pci_unregister_driver(&driver);
2997 asihpi_exit();
2998}
2999
3000module_init(snd_asihpi_init)
3001module_exit(snd_asihpi_exit)
3002