blob: f4b9e2b7ae87ae1df0b5dfa374c1e2528b2232b7 [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#include "hpi_internal.h"
26#include "hpimsginit.h"
27#include "hpioctl.h"
28
29#include <linux/pci.h>
30#include <linux/init.h>
31#include <linux/jiffies.h>
32#include <linux/slab.h>
33#include <linux/time.h>
34#include <linux/wait.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040035#include <linux/module.h>
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020036#include <sound/core.h>
37#include <sound/control.h>
38#include <sound/pcm.h>
39#include <sound/pcm_params.h>
40#include <sound/info.h>
41#include <sound/initval.h>
42#include <sound/tlv.h>
43#include <sound/hwdep.h>
44
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020045MODULE_LICENSE("GPL");
46MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
47MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
48
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +130049#if defined CONFIG_SND_DEBUG_VERBOSE
50/**
51 * snd_printddd - very verbose debug printk
52 * @format: format string
53 *
54 * Works like snd_printk() for debugging purposes.
55 * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set.
56 * Must set snd module debug parameter to 3 to enable at runtime.
57 */
58#define snd_printddd(format, args...) \
59 __snd_printk(3, __FILE__, __LINE__, format, ##args)
60#else
Eliot Blennerhassettb0096a62011-04-05 20:55:46 +120061#define snd_printddd(format, args...) do { } while (0)
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +130062#endif
63
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020064static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */
65static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
66static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
67static int enable_hpi_hwdep = 1;
68
69module_param_array(index, int, NULL, S_IRUGO);
70MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard.");
71
72module_param_array(id, charp, NULL, S_IRUGO);
73MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard.");
74
75module_param_array(enable, bool, NULL, S_IRUGO);
76MODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard.");
77
78module_param(enable_hpi_hwdep, bool, S_IRUGO|S_IWUSR);
79MODULE_PARM_DESC(enable_hpi_hwdep,
80 "ALSA enable HPI hwdep for AudioScience soundcard ");
81
82/* identify driver */
83#ifdef KERNEL_ALSA_BUILD
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +130084static char *build_info = "Built using headers from kernel source";
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020085module_param(build_info, charp, S_IRUGO);
86MODULE_PARM_DESC(build_info, "built using headers from kernel source");
87#else
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +130088static char *build_info = "Built within ALSA source";
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020089module_param(build_info, charp, S_IRUGO);
90MODULE_PARM_DESC(build_info, "built within ALSA source");
91#endif
92
93/* set to 1 to dump every control from adapter to log */
94static const int mixer_dump;
95
96#define DEFAULT_SAMPLERATE 44100
97static int adapter_fs = DEFAULT_SAMPLERATE;
98
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +020099/* defaults */
100#define PERIODS_MIN 2
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300101#define PERIOD_BYTES_MIN 2048
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200102#define BUFFER_BYTES_MAX (512 * 1024)
103
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200104#define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
105
106struct clk_source {
107 int source;
108 int index;
109 char *name;
110};
111
112struct clk_cache {
113 int count;
114 int has_local;
115 struct clk_source s[MAX_CLOCKSOURCES];
116};
117
118/* Per card data */
119struct snd_card_asihpi {
120 struct snd_card *card;
121 struct pci_dev *pci;
122 u16 adapter_index;
123 u32 serial_number;
124 u16 type;
125 u16 version;
126 u16 num_outstreams;
127 u16 num_instreams;
128
129 u32 h_mixer;
130 struct clk_cache cc;
131
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200132 u16 can_dma;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200133 u16 support_grouping;
134 u16 support_mrx;
135 u16 update_interval_frames;
136 u16 in_max_chans;
137 u16 out_max_chans;
138};
139
140/* Per stream data */
141struct snd_card_asihpi_pcm {
142 struct timer_list timer;
143 unsigned int respawn_timer;
144 unsigned int hpi_buffer_attached;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300145 unsigned int buffer_bytes;
146 unsigned int period_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200147 unsigned int bytes_per_sec;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300148 unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
149 unsigned int pcm_buf_dma_ofs; /* DMA R/W offset in buffer */
150 unsigned int pcm_buf_elapsed_dma_ofs; /* DMA R/W offset in buffer */
Eliot Blennerhassett0b7ce9e2011-04-05 20:55:43 +1200151 unsigned int drained_count;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200152 struct snd_pcm_substream *substream;
153 u32 h_stream;
154 struct hpi_format format;
155};
156
157/* universal stream verbs work with out or in stream handles */
158
159/* Functions to allow driver to give a buffer to HPI for busmastering */
160
161static u16 hpi_stream_host_buffer_attach(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200162 u32 h_stream, /* handle to outstream. */
163 u32 size_in_bytes, /* size in bytes of bus mastering buffer */
164 u32 pci_address
165)
166{
167 struct hpi_message hm;
168 struct hpi_response hr;
169 unsigned int obj = hpi_handle_object(h_stream);
170
171 if (!h_stream)
172 return HPI_ERROR_INVALID_OBJ;
173 hpi_init_message_response(&hm, &hr, obj,
174 obj == HPI_OBJ_OSTREAM ?
175 HPI_OSTREAM_HOSTBUFFER_ALLOC :
176 HPI_ISTREAM_HOSTBUFFER_ALLOC);
177
178 hpi_handle_to_indexes(h_stream, &hm.adapter_index,
179 &hm.obj_index);
180
181 hm.u.d.u.buffer.buffer_size = size_in_bytes;
182 hm.u.d.u.buffer.pci_address = pci_address;
183 hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER;
184 hpi_send_recv(&hm, &hr);
185 return hr.error;
186}
187
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300188static u16 hpi_stream_host_buffer_detach(u32 h_stream)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200189{
190 struct hpi_message hm;
191 struct hpi_response hr;
192 unsigned int obj = hpi_handle_object(h_stream);
193
194 if (!h_stream)
195 return HPI_ERROR_INVALID_OBJ;
196
197 hpi_init_message_response(&hm, &hr, obj,
198 obj == HPI_OBJ_OSTREAM ?
199 HPI_OSTREAM_HOSTBUFFER_FREE :
200 HPI_ISTREAM_HOSTBUFFER_FREE);
201
202 hpi_handle_to_indexes(h_stream, &hm.adapter_index,
203 &hm.obj_index);
204 hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER;
205 hpi_send_recv(&hm, &hr);
206 return hr.error;
207}
208
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300209static inline u16 hpi_stream_start(u32 h_stream)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200210{
211 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300212 return hpi_outstream_start(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200213 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300214 return hpi_instream_start(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200215}
216
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300217static inline u16 hpi_stream_stop(u32 h_stream)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200218{
219 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300220 return hpi_outstream_stop(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200221 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300222 return hpi_instream_stop(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200223}
224
225static inline u16 hpi_stream_get_info_ex(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200226 u32 h_stream,
227 u16 *pw_state,
228 u32 *pbuffer_size,
229 u32 *pdata_in_buffer,
230 u32 *psample_count,
231 u32 *pauxiliary_data
232)
233{
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300234 u16 e;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200235 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300236 e = hpi_outstream_get_info_ex(h_stream, pw_state,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200237 pbuffer_size, pdata_in_buffer,
238 psample_count, pauxiliary_data);
239 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300240 e = hpi_instream_get_info_ex(h_stream, pw_state,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200241 pbuffer_size, pdata_in_buffer,
242 psample_count, pauxiliary_data);
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300243 return e;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200244}
245
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300246static inline u16 hpi_stream_group_add(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200247 u32 h_master,
248 u32 h_stream)
249{
250 if (hpi_handle_object(h_master) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300251 return hpi_outstream_group_add(h_master, h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200252 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300253 return hpi_instream_group_add(h_master, h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200254}
255
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300256static inline u16 hpi_stream_group_reset(u32 h_stream)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200257{
258 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300259 return hpi_outstream_group_reset(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200260 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300261 return hpi_instream_group_reset(h_stream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200262}
263
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300264static inline u16 hpi_stream_group_get_map(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200265 u32 h_stream, u32 *mo, u32 *mi)
266{
267 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300268 return hpi_outstream_group_get_map(h_stream, mo, mi);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200269 else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300270 return hpi_instream_group_get_map(h_stream, mo, mi);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200271}
272
273static u16 handle_error(u16 err, int line, char *filename)
274{
275 if (err)
276 printk(KERN_WARNING
277 "in file %s, line %d: HPI error %d\n",
278 filename, line, err);
279 return err;
280}
281
282#define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__)
283
284/***************************** GENERAL PCM ****************/
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200285
286static void print_hwparams(struct snd_pcm_substream *substream,
287 struct snd_pcm_hw_params *p)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200288{
Eliot Blennerhassett0a17e992011-07-22 15:52:44 +1200289 char name[16];
290 snd_pcm_debug_name(substream, name, sizeof(name));
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200291 snd_printd("%s HWPARAMS\n", name);
292 snd_printd(" samplerate %d Hz\n", params_rate(p));
293 snd_printd(" channels %d\n", params_channels(p));
294 snd_printd(" format %d\n", params_format(p));
295 snd_printd(" subformat %d\n", params_subformat(p));
296 snd_printd(" buffer %d B\n", params_buffer_bytes(p));
297 snd_printd(" period %d B\n", params_period_bytes(p));
298 snd_printd(" access %d\n", params_access(p));
299 snd_printd(" period_size %d\n", params_period_size(p));
300 snd_printd(" periods %d\n", params_periods(p));
301 snd_printd(" buffer_size %d\n", params_buffer_size(p));
302 snd_printd(" %d B/s\n", params_rate(p) *
303 params_channels(p) *
304 snd_pcm_format_width(params_format(p)) / 8);
305
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200306}
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200307
308static snd_pcm_format_t hpi_to_alsa_formats[] = {
309 -1, /* INVALID */
310 SNDRV_PCM_FORMAT_U8, /* HPI_FORMAT_PCM8_UNSIGNED 1 */
311 SNDRV_PCM_FORMAT_S16, /* HPI_FORMAT_PCM16_SIGNED 2 */
312 -1, /* HPI_FORMAT_MPEG_L1 3 */
313 SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L2 4 */
314 SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L3 5 */
315 -1, /* HPI_FORMAT_DOLBY_AC2 6 */
316 -1, /* HPI_FORMAT_DOLBY_AC3 7 */
317 SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN 8 */
318 -1, /* HPI_FORMAT_AA_TAGIT1_HITS 9 */
319 -1, /* HPI_FORMAT_AA_TAGIT1_INSERTS 10 */
320 SNDRV_PCM_FORMAT_S32, /* HPI_FORMAT_PCM32_SIGNED 11 */
321 -1, /* HPI_FORMAT_RAW_BITSTREAM 12 */
322 -1, /* HPI_FORMAT_AA_TAGIT1_HITS_EX1 13 */
323 SNDRV_PCM_FORMAT_FLOAT, /* HPI_FORMAT_PCM32_FLOAT 14 */
324#if 1
325 /* ALSA can't handle 3 byte sample size together with power-of-2
326 * constraint on buffer_bytes, so disable this format
327 */
328 -1
329#else
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300330 /* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200331#endif
332};
333
334
335static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,
336 u16 *hpi_format)
337{
338 u16 format;
339
340 for (format = HPI_FORMAT_PCM8_UNSIGNED;
341 format <= HPI_FORMAT_PCM24_SIGNED; format++) {
342 if (hpi_to_alsa_formats[format] == alsa_format) {
343 *hpi_format = format;
344 return 0;
345 }
346 }
347
348 snd_printd(KERN_WARNING "failed match for alsa format %d\n",
349 alsa_format);
350 *hpi_format = 0;
351 return -EINVAL;
352}
353
354static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
355 struct snd_pcm_hardware *pcmhw)
356{
357 u16 err;
358 u32 h_control;
359 u32 sample_rate;
360 int idx;
361 unsigned int rate_min = 200000;
362 unsigned int rate_max = 0;
363 unsigned int rates = 0;
364
365 if (asihpi->support_mrx) {
366 rates |= SNDRV_PCM_RATE_CONTINUOUS;
367 rates |= SNDRV_PCM_RATE_8000_96000;
368 rate_min = 8000;
369 rate_max = 100000;
370 } else {
371 /* on cards without SRC,
372 valid rates are determined by sampleclock */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300373 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200374 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
375 HPI_CONTROL_SAMPLECLOCK, &h_control);
376 if (err) {
377 snd_printk(KERN_ERR
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300378 "No local sampleclock, err %d\n", err);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200379 }
380
Eliot Blennerhassett7bf76c32011-03-25 15:25:46 +1300381 for (idx = -1; idx < 100; idx++) {
382 if (idx == -1) {
383 if (hpi_sample_clock_get_sample_rate(h_control,
384 &sample_rate))
385 continue;
386 } else if (hpi_sample_clock_query_local_rate(h_control,
387 idx, &sample_rate)) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200388 break;
389 }
390
391 rate_min = min(rate_min, sample_rate);
392 rate_max = max(rate_max, sample_rate);
393
394 switch (sample_rate) {
395 case 5512:
396 rates |= SNDRV_PCM_RATE_5512;
397 break;
398 case 8000:
399 rates |= SNDRV_PCM_RATE_8000;
400 break;
401 case 11025:
402 rates |= SNDRV_PCM_RATE_11025;
403 break;
404 case 16000:
405 rates |= SNDRV_PCM_RATE_16000;
406 break;
407 case 22050:
408 rates |= SNDRV_PCM_RATE_22050;
409 break;
410 case 32000:
411 rates |= SNDRV_PCM_RATE_32000;
412 break;
413 case 44100:
414 rates |= SNDRV_PCM_RATE_44100;
415 break;
416 case 48000:
417 rates |= SNDRV_PCM_RATE_48000;
418 break;
419 case 64000:
420 rates |= SNDRV_PCM_RATE_64000;
421 break;
422 case 88200:
423 rates |= SNDRV_PCM_RATE_88200;
424 break;
425 case 96000:
426 rates |= SNDRV_PCM_RATE_96000;
427 break;
428 case 176400:
429 rates |= SNDRV_PCM_RATE_176400;
430 break;
431 case 192000:
432 rates |= SNDRV_PCM_RATE_192000;
433 break;
434 default: /* some other rate */
435 rates |= SNDRV_PCM_RATE_KNOT;
436 }
437 }
438 }
439
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200440 pcmhw->rates = rates;
441 pcmhw->rate_min = rate_min;
442 pcmhw->rate_max = rate_max;
443}
444
445static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
446 struct snd_pcm_hw_params *params)
447{
448 struct snd_pcm_runtime *runtime = substream->runtime;
449 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
450 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
451 int err;
452 u16 format;
Kulikov Vasiliy315e8f72010-07-15 22:48:19 +0400453 int width;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200454 unsigned int bytes_per_sec;
455
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200456 print_hwparams(substream, params);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200457 err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
458 if (err < 0)
459 return err;
460 err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format);
461 if (err)
462 return err;
463
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200464 hpi_handle_error(hpi_format_create(&dpcm->format,
465 params_channels(params),
466 format, params_rate(params), 0, 0));
467
468 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300469 if (hpi_instream_reset(dpcm->h_stream) != 0)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200470 return -EINVAL;
471
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300472 if (hpi_instream_set_format(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200473 dpcm->h_stream, &dpcm->format) != 0)
474 return -EINVAL;
475 }
476
477 dpcm->hpi_buffer_attached = 0;
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200478 if (card->can_dma) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300479 err = hpi_stream_host_buffer_attach(dpcm->h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200480 params_buffer_bytes(params), runtime->dma_addr);
481 if (err == 0) {
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300482 snd_printdd(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200483 "stream_host_buffer_attach succeeded %u %lu\n",
484 params_buffer_bytes(params),
485 (unsigned long)runtime->dma_addr);
486 } else {
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300487 snd_printd("stream_host_buffer_attach error %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200488 err);
489 return -ENOMEM;
490 }
491
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300492 err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200493 &dpcm->hpi_buffer_attached,
494 NULL, NULL, NULL);
495
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300496 snd_printdd("stream_host_buffer_attach status 0x%x\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200497 dpcm->hpi_buffer_attached);
498 }
499 bytes_per_sec = params_rate(params) * params_channels(params);
Kulikov Vasiliy315e8f72010-07-15 22:48:19 +0400500 width = snd_pcm_format_width(params_format(params));
501 bytes_per_sec *= width;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200502 bytes_per_sec /= 8;
Kulikov Vasiliy315e8f72010-07-15 22:48:19 +0400503 if (width < 0 || bytes_per_sec == 0)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200504 return -EINVAL;
505
506 dpcm->bytes_per_sec = bytes_per_sec;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300507 dpcm->buffer_bytes = params_buffer_bytes(params);
508 dpcm->period_bytes = params_period_bytes(params);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200509
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200510 return 0;
511}
512
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300513static int
514snd_card_asihpi_hw_free(struct snd_pcm_substream *substream)
515{
516 struct snd_pcm_runtime *runtime = substream->runtime;
517 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
518 if (dpcm->hpi_buffer_attached)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300519 hpi_stream_host_buffer_detach(dpcm->h_stream);
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300520
521 snd_pcm_lib_free_pages(substream);
522 return 0;
523}
524
525static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)
526{
527 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
528 kfree(dpcm);
529}
530
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200531static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
532 substream)
533{
534 struct snd_pcm_runtime *runtime = substream->runtime;
535 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
536 int expiry;
537
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300538 expiry = HZ / 200;
539 /*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300540 expiry = max(expiry, 1); /* don't let it be zero! */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200541 dpcm->timer.expires = jiffies + expiry;
542 dpcm->respawn_timer = 1;
543 add_timer(&dpcm->timer);
544}
545
546static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
547{
548 struct snd_pcm_runtime *runtime = substream->runtime;
549 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
550
551 dpcm->respawn_timer = 0;
552 del_timer(&dpcm->timer);
553}
554
555static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
556 int cmd)
557{
558 struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
559 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
560 struct snd_pcm_substream *s;
561 u16 e;
Eliot Blennerhassett0a17e992011-07-22 15:52:44 +1200562 char name[16];
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200563
Eliot Blennerhassett0a17e992011-07-22 15:52:44 +1200564 snd_pcm_debug_name(substream, name, sizeof(name));
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200565 snd_printdd("%s trigger\n", name);
566
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200567 switch (cmd) {
568 case SNDRV_PCM_TRIGGER_START:
569 snd_pcm_group_for_each_entry(s, substream) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300570 struct snd_pcm_runtime *runtime = s->runtime;
571 struct snd_card_asihpi_pcm *ds = runtime->private_data;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200572
573 if (snd_pcm_substream_chip(s) != card)
574 continue;
575
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300576 /* don't link Cap and Play */
577 if (substream->stream != s->stream)
578 continue;
579
Eliot Blennerhassett0b7ce9e2011-04-05 20:55:43 +1200580 ds->drained_count = 0;
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200581 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200582 /* How do I know how much valid data is present
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300583 * in buffer? Must be at least one period!
584 * Guessing 2 periods, but if
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200585 * buffer is bigger it may contain even more
586 * data??
587 */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300588 unsigned int preload = ds->period_bytes * 1;
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300589 snd_printddd("%d preload x%x\n", s->number, preload);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200590 hpi_handle_error(hpi_outstream_write_buf(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300591 ds->h_stream,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300592 &runtime->dma_area[0],
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200593 preload,
594 &ds->format));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300595 ds->pcm_buf_host_rw_ofs = preload;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200596 }
597
598 if (card->support_grouping) {
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200599 snd_printdd("%d group\n", s->number);
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300600 e = hpi_stream_group_add(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200601 dpcm->h_stream,
602 ds->h_stream);
603 if (!e) {
604 snd_pcm_trigger_done(s, substream);
605 } else {
606 hpi_handle_error(e);
607 break;
608 }
609 } else
610 break;
611 }
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300612 snd_printdd("start\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200613 /* start the master stream */
614 snd_card_asihpi_pcm_timer_start(substream);
Eliot Blennerhassettc4ed97d2011-02-10 17:26:20 +1300615 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200616 !card->can_dma)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300617 hpi_handle_error(hpi_stream_start(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200618 break;
619
620 case SNDRV_PCM_TRIGGER_STOP:
621 snd_card_asihpi_pcm_timer_stop(substream);
622 snd_pcm_group_for_each_entry(s, substream) {
623 if (snd_pcm_substream_chip(s) != card)
624 continue;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300625 /* don't link Cap and Play */
626 if (substream->stream != s->stream)
627 continue;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200628
629 /*? workaround linked streams don't
630 transition to SETUP 20070706*/
631 s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
632
633 if (card->support_grouping) {
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200634 snd_printdd("%d group\n", s->number);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200635 snd_pcm_trigger_done(s, substream);
636 } else
637 break;
638 }
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300639 snd_printdd("stop\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200640
641 /* _prepare and _hwparams reset the stream */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300642 hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200643 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
644 hpi_handle_error(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300645 hpi_outstream_reset(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200646
647 if (card->support_grouping)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300648 hpi_handle_error(hpi_stream_group_reset(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200649 break;
650
651 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300652 snd_printdd("pause release\n");
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300653 hpi_handle_error(hpi_stream_start(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200654 snd_card_asihpi_pcm_timer_start(substream);
655 break;
656 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300657 snd_printdd("pause\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200658 snd_card_asihpi_pcm_timer_stop(substream);
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300659 hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200660 break;
661 default:
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300662 snd_printd(KERN_ERR "\tINVALID\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200663 return -EINVAL;
664 }
665
666 return 0;
667}
668
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200669/*algorithm outline
670 Without linking degenerates to getting single stream pos etc
671 Without mmap 2nd loop degenerates to snd_pcm_period_elapsed
672*/
673/*
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300674pcm_buf_dma_ofs=get_buf_pos(s);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200675for_each_linked_stream(s) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300676 pcm_buf_dma_ofs=get_buf_pos(s);
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300677 min_buf_pos = modulo_min(min_buf_pos, pcm_buf_dma_ofs, buffer_bytes)
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300678 new_data = min(new_data, calc_new_data(pcm_buf_dma_ofs,irq_pos)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200679}
680timer.expires = jiffies + predict_next_period_ready(min_buf_pos);
681for_each_linked_stream(s) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300682 s->pcm_buf_dma_ofs = min_buf_pos;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300683 if (new_data > period_bytes) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200684 if (mmap) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300685 irq_pos = (irq_pos + period_bytes) % buffer_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200686 if (playback) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300687 write(period_bytes);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200688 } else {
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300689 read(period_bytes);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200690 }
691 }
692 snd_pcm_period_elapsed(s);
693 }
694}
695*/
696
697/** Minimum of 2 modulo values. Works correctly when the difference between
698* the values is less than half the modulus
699*/
700static inline unsigned int modulo_min(unsigned int a, unsigned int b,
701 unsigned long int modulus)
702{
703 unsigned int result;
704 if (((a-b) % modulus) < (modulus/2))
705 result = b;
706 else
707 result = a;
708
709 return result;
710}
711
712/** Timer function, equivalent to interrupt service routine for cards
713*/
714static void snd_card_asihpi_timer_function(unsigned long data)
715{
716 struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300717 struct snd_pcm_substream *substream = dpcm->substream;
718 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200719 struct snd_pcm_runtime *runtime;
720 struct snd_pcm_substream *s;
721 unsigned int newdata = 0;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300722 unsigned int pcm_buf_dma_ofs, min_buf_pos = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200723 unsigned int remdata, xfercount, next_jiffies;
724 int first = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300725 int loops = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200726 u16 state;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300727 u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
Eliot Blennerhassett0a17e992011-07-22 15:52:44 +1200728 char name[16];
729
730 snd_pcm_debug_name(substream, name, sizeof(name));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200731
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200732 snd_printdd("%s snd_card_asihpi_timer_function\n", name);
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300733
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200734 /* find minimum newdata and buffer pos in group */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300735 snd_pcm_group_for_each_entry(s, substream) {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200736 struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
737 runtime = s->runtime;
738
739 if (snd_pcm_substream_chip(s) != card)
740 continue;
741
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300742 /* don't link Cap and Play */
743 if (substream->stream != s->stream)
744 continue;
745
746 hpi_handle_error(hpi_stream_get_info_ex(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200747 ds->h_stream, &state,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300748 &buffer_size, &bytes_avail,
749 &samples_played, &on_card_bytes));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200750
751 /* number of bytes in on-card buffer */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300752 runtime->delay = on_card_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200753
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200754 if (!card->can_dma)
755 on_card_bytes = bytes_avail;
756
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300757 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300758 pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300759 if (state == HPI_STATE_STOPPED) {
760 if ((bytes_avail == 0) &&
761 (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
762 hpi_handle_error(hpi_stream_start(ds->h_stream));
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300763 snd_printdd("P%d start\n", s->number);
Eliot Blennerhassett0b7ce9e2011-04-05 20:55:43 +1200764 ds->drained_count = 0;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300765 }
766 } else if (state == HPI_STATE_DRAINED) {
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +1300767 snd_printd(KERN_WARNING "P%d drained\n",
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300768 s->number);
Eliot Blennerhassett0b7ce9e2011-04-05 20:55:43 +1200769 ds->drained_count++;
770 if (ds->drained_count > 2) {
771 snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
772 continue;
773 }
774 } else {
775 ds->drained_count = 0;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300776 }
777 } else
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300778 pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200779
780 if (first) {
781 /* can't statically init min when wrap is involved */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300782 min_buf_pos = pcm_buf_dma_ofs;
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300783 newdata = (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200784 first = 0;
785 } else {
786 min_buf_pos =
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300787 modulo_min(min_buf_pos, pcm_buf_dma_ofs, UINT_MAX+1L);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200788 newdata = min(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300789 (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200790 newdata);
791 }
792
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200793 snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200794 (unsigned long)frames_to_bytes(runtime,
795 runtime->status->hw_ptr),
796 (unsigned long)frames_to_bytes(runtime,
797 runtime->control->appl_ptr));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300798
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200799 snd_printdd("%d S=%d, "
800 "rw=0x%04X, dma=0x%04X, left=0x%04X, "
801 "aux=0x%04X space=0x%04X\n",
802 s->number, state,
803 ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs,
804 (int)bytes_avail,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300805 (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 Blennerhassetta6477132011-04-05 20:55:42 +1200823 snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%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 Blennerhassettf3d145a2011-04-05 20:55:44 +1200835 if (xfercount &&
836 /* Limit use of on card fifo for playback */
837 ((on_card_bytes <= ds->period_bytes) ||
838 (s->stream == SNDRV_PCM_STREAM_CAPTURE)))
839
840 {
841
842 unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes;
843 unsigned int xfer1, xfer2;
844 char *pd = &s->runtime->dma_area[buf_ofs];
845
Eliot Blennerhassettb0096a62011-04-05 20:55:46 +1200846 if (card->can_dma) { /* buffer wrap is handled at lower level */
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200847 xfer1 = xfercount;
848 xfer2 = 0;
849 } else {
850 xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs);
851 xfer2 = xfercount - xfer1;
852 }
853
854 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
855 snd_printddd("P%d write1 0x%04X 0x%04X\n",
856 s->number, xfer1, buf_ofs);
857 hpi_handle_error(
858 hpi_outstream_write_buf(
859 ds->h_stream, pd, xfer1,
860 &ds->format));
861
862 if (xfer2) {
863 pd = s->runtime->dma_area;
864
865 snd_printddd("P%d write2 0x%04X 0x%04X\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200866 s->number,
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200867 xfercount - xfer1, buf_ofs);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200868 hpi_handle_error(
869 hpi_outstream_write_buf(
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200870 ds->h_stream, pd,
871 xfercount - xfer1,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200872 &ds->format));
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200873 }
874 } else {
875 snd_printddd("C%d read1 0x%04x\n",
876 s->number, xfer1);
877 hpi_handle_error(
878 hpi_instream_read_buf(
879 ds->h_stream,
880 pd, xfer1));
881 if (xfer2) {
882 pd = s->runtime->dma_area;
883 snd_printddd("C%d read2 0x%04x\n",
884 s->number, xfer2);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200885 hpi_handle_error(
886 hpi_instream_read_buf(
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300887 ds->h_stream,
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200888 pd, xfer2));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200889 }
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +1200890 }
891 ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300892 ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200893 snd_pcm_period_elapsed(s);
894 }
895 }
896
897 if (dpcm->respawn_timer)
898 add_timer(&dpcm->timer);
899}
900
901/***************************** PLAYBACK OPS ****************/
902static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
903 unsigned int cmd, void *arg)
904{
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200905 snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200906 return snd_pcm_lib_ioctl(substream, cmd, arg);
907}
908
909static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
910 substream)
911{
912 struct snd_pcm_runtime *runtime = substream->runtime;
913 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
914
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200915 snd_printdd("P%d prepare\n", substream->number);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200916
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300917 hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +1300918 dpcm->pcm_buf_host_rw_ofs = 0;
919 dpcm->pcm_buf_dma_ofs = 0;
920 dpcm->pcm_buf_elapsed_dma_ofs = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200921 return 0;
922}
923
924static snd_pcm_uframes_t
925snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
926{
927 struct snd_pcm_runtime *runtime = substream->runtime;
928 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
929 snd_pcm_uframes_t ptr;
930
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300931 ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
Eliot Blennerhassetta6477132011-04-05 20:55:42 +1200932 snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200933 return ptr;
934}
935
936static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
937 u32 h_stream,
938 struct snd_pcm_hardware *pcmhw)
939{
940 struct hpi_format hpi_format;
941 u16 format;
942 u16 err;
943 u32 h_control;
944 u32 sample_rate = 48000;
945
946 /* on cards without SRC, must query at valid rate,
947 * maybe set by external sync
948 */
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300949 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200950 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
951 HPI_CONTROL_SAMPLECLOCK, &h_control);
952
953 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300954 err = hpi_sample_clock_get_sample_rate(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200955 &sample_rate);
956
957 for (format = HPI_FORMAT_PCM8_UNSIGNED;
958 format <= HPI_FORMAT_PCM24_SIGNED; format++) {
959 err = hpi_format_create(&hpi_format,
960 2, format, sample_rate, 128000, 0);
961 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300962 err = hpi_outstream_query_format(h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200963 &hpi_format);
964 if (!err && (hpi_to_alsa_formats[format] != -1))
965 pcmhw->formats |=
966 (1ULL << hpi_to_alsa_formats[format]);
967 }
968}
969
970static struct snd_pcm_hardware snd_card_asihpi_playback = {
971 .channels_min = 1,
972 .channels_max = 2,
973 .buffer_bytes_max = BUFFER_BYTES_MAX,
974 .period_bytes_min = PERIOD_BYTES_MIN,
975 .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
976 .periods_min = PERIODS_MIN,
977 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
978 .fifo_size = 0,
979};
980
981static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
982{
983 struct snd_pcm_runtime *runtime = substream->runtime;
984 struct snd_card_asihpi_pcm *dpcm;
985 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
986 int err;
987
988 dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
989 if (dpcm == NULL)
990 return -ENOMEM;
991
992 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +1300993 hpi_outstream_open(card->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +0200994 substream->number, &dpcm->h_stream);
995 hpi_handle_error(err);
996 if (err)
997 kfree(dpcm);
998 if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
999 return -EBUSY;
1000 if (err)
1001 return -EIO;
1002
1003 /*? also check ASI5000 samplerate source
1004 If external, only support external rate.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001005 If internal and other stream playing, can't switch
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001006 */
1007
1008 init_timer(&dpcm->timer);
1009 dpcm->timer.data = (unsigned long) dpcm;
1010 dpcm->timer.function = snd_card_asihpi_timer_function;
1011 dpcm->substream = substream;
1012 runtime->private_data = dpcm;
1013 runtime->private_free = snd_card_asihpi_runtime_free;
1014
1015 snd_card_asihpi_playback.channels_max = card->out_max_chans;
1016 /*?snd_card_asihpi_playback.period_bytes_min =
1017 card->out_max_chans * 4096; */
1018
1019 snd_card_asihpi_playback_format(card, dpcm->h_stream,
1020 &snd_card_asihpi_playback);
1021
1022 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_playback);
1023
1024 snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED |
1025 SNDRV_PCM_INFO_DOUBLE |
1026 SNDRV_PCM_INFO_BATCH |
1027 SNDRV_PCM_INFO_BLOCK_TRANSFER |
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +12001028 SNDRV_PCM_INFO_PAUSE |
1029 SNDRV_PCM_INFO_MMAP |
1030 SNDRV_PCM_INFO_MMAP_VALID;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001031
1032 if (card->support_grouping)
1033 snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
1034
1035 /* struct is copied, so can create initializer dynamically */
1036 runtime->hw = snd_card_asihpi_playback;
1037
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +12001038 if (card->can_dma)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001039 err = snd_pcm_hw_constraint_pow2(runtime, 0,
1040 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1041 if (err < 0)
1042 return err;
1043
1044 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1045 card->update_interval_frames);
Eliot Blennerhassett26aebef2011-03-25 15:25:47 +13001046
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001047 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001048 card->update_interval_frames * 2, UINT_MAX);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001049
1050 snd_pcm_set_sync(substream);
1051
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +13001052 snd_printdd("playback open\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001053
1054 return 0;
1055}
1056
1057static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
1058{
1059 struct snd_pcm_runtime *runtime = substream->runtime;
1060 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1061
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001062 hpi_handle_error(hpi_outstream_close(dpcm->h_stream));
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +13001063 snd_printdd("playback close\n");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001064
1065 return 0;
1066}
1067
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001068static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
1069 .open = snd_card_asihpi_playback_open,
1070 .close = snd_card_asihpi_playback_close,
1071 .ioctl = snd_card_asihpi_playback_ioctl,
1072 .hw_params = snd_card_asihpi_pcm_hw_params,
1073 .hw_free = snd_card_asihpi_hw_free,
1074 .prepare = snd_card_asihpi_playback_prepare,
1075 .trigger = snd_card_asihpi_trigger,
1076 .pointer = snd_card_asihpi_playback_pointer,
1077};
1078
1079/***************************** CAPTURE OPS ****************/
1080static snd_pcm_uframes_t
1081snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
1082{
1083 struct snd_pcm_runtime *runtime = substream->runtime;
1084 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1085
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +13001086 snd_printddd("capture pointer %d=%d\n",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001087 substream->number, dpcm->pcm_buf_dma_ofs);
1088 /* NOTE Unlike playback can't use actual samples_played
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001089 for the capture position, because those samples aren't yet in
1090 the local buffer available for reading.
1091 */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001092 return bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001093}
1094
1095static int snd_card_asihpi_capture_ioctl(struct snd_pcm_substream *substream,
1096 unsigned int cmd, void *arg)
1097{
1098 return snd_pcm_lib_ioctl(substream, cmd, arg);
1099}
1100
1101static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
1102{
1103 struct snd_pcm_runtime *runtime = substream->runtime;
1104 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1105
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001106 hpi_handle_error(hpi_instream_reset(dpcm->h_stream));
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001107 dpcm->pcm_buf_host_rw_ofs = 0;
1108 dpcm->pcm_buf_dma_ofs = 0;
1109 dpcm->pcm_buf_elapsed_dma_ofs = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001110
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +13001111 snd_printdd("Capture Prepare %d\n", substream->number);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001112 return 0;
1113}
1114
1115
1116
1117static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
1118 u32 h_stream,
1119 struct snd_pcm_hardware *pcmhw)
1120{
1121 struct hpi_format hpi_format;
1122 u16 format;
1123 u16 err;
1124 u32 h_control;
1125 u32 sample_rate = 48000;
1126
1127 /* on cards without SRC, must query at valid rate,
1128 maybe set by external sync */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001129 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001130 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
1131 HPI_CONTROL_SAMPLECLOCK, &h_control);
1132
1133 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001134 err = hpi_sample_clock_get_sample_rate(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001135 &sample_rate);
1136
1137 for (format = HPI_FORMAT_PCM8_UNSIGNED;
1138 format <= HPI_FORMAT_PCM24_SIGNED; format++) {
1139
1140 err = hpi_format_create(&hpi_format, 2, format,
1141 sample_rate, 128000, 0);
1142 if (!err)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001143 err = hpi_instream_query_format(h_stream,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001144 &hpi_format);
1145 if (!err)
1146 pcmhw->formats |=
1147 (1ULL << hpi_to_alsa_formats[format]);
1148 }
1149}
1150
1151
1152static struct snd_pcm_hardware snd_card_asihpi_capture = {
1153 .channels_min = 1,
1154 .channels_max = 2,
1155 .buffer_bytes_max = BUFFER_BYTES_MAX,
1156 .period_bytes_min = PERIOD_BYTES_MIN,
1157 .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
1158 .periods_min = PERIODS_MIN,
1159 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
1160 .fifo_size = 0,
1161};
1162
1163static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
1164{
1165 struct snd_pcm_runtime *runtime = substream->runtime;
1166 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
1167 struct snd_card_asihpi_pcm *dpcm;
1168 int err;
1169
1170 dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
1171 if (dpcm == NULL)
1172 return -ENOMEM;
1173
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +13001174 snd_printdd("capture open adapter %d stream %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001175 card->adapter_index, substream->number);
1176
1177 err = hpi_handle_error(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001178 hpi_instream_open(card->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001179 substream->number, &dpcm->h_stream));
1180 if (err)
1181 kfree(dpcm);
1182 if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
1183 return -EBUSY;
1184 if (err)
1185 return -EIO;
1186
1187
1188 init_timer(&dpcm->timer);
1189 dpcm->timer.data = (unsigned long) dpcm;
1190 dpcm->timer.function = snd_card_asihpi_timer_function;
1191 dpcm->substream = substream;
1192 runtime->private_data = dpcm;
1193 runtime->private_free = snd_card_asihpi_runtime_free;
1194
1195 snd_card_asihpi_capture.channels_max = card->in_max_chans;
1196 snd_card_asihpi_capture_format(card, dpcm->h_stream,
1197 &snd_card_asihpi_capture);
1198 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture);
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +12001199 snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |
1200 SNDRV_PCM_INFO_MMAP |
1201 SNDRV_PCM_INFO_MMAP_VALID;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001202
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001203 if (card->support_grouping)
1204 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
1205
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001206 runtime->hw = snd_card_asihpi_capture;
1207
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +12001208 if (card->can_dma)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001209 err = snd_pcm_hw_constraint_pow2(runtime, 0,
1210 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1211 if (err < 0)
1212 return err;
1213
1214 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1215 card->update_interval_frames);
1216 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1217 card->update_interval_frames * 2, UINT_MAX);
1218
1219 snd_pcm_set_sync(substream);
1220
1221 return 0;
1222}
1223
1224static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
1225{
1226 struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
1227
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001228 hpi_handle_error(hpi_instream_close(dpcm->h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001229 return 0;
1230}
1231
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001232static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
1233 .open = snd_card_asihpi_capture_open,
1234 .close = snd_card_asihpi_capture_close,
1235 .ioctl = snd_card_asihpi_capture_ioctl,
1236 .hw_params = snd_card_asihpi_pcm_hw_params,
1237 .hw_free = snd_card_asihpi_hw_free,
1238 .prepare = snd_card_asihpi_capture_prepare,
1239 .trigger = snd_card_asihpi_trigger,
1240 .pointer = snd_card_asihpi_capture_pointer,
1241};
1242
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001243static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
1244 int device, int substreams)
1245{
1246 struct snd_pcm *pcm;
1247 int err;
1248
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001249 err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001250 asihpi->num_outstreams, asihpi->num_instreams,
1251 &pcm);
1252 if (err < 0)
1253 return err;
1254 /* pointer to ops struct is stored, dont change ops afterwards! */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001255 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1256 &snd_card_asihpi_playback_mmap_ops);
1257 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1258 &snd_card_asihpi_capture_mmap_ops);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001259
1260 pcm->private_data = asihpi;
1261 pcm->info_flags = 0;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001262 strcpy(pcm->name, "Asihpi PCM");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001263
1264 /*? do we want to emulate MMAP for non-BBM cards?
1265 Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
1266 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1267 snd_dma_pci_data(asihpi->pci),
1268 64*1024, BUFFER_BYTES_MAX);
1269
1270 return 0;
1271}
1272
1273/***************************** MIXER CONTROLS ****************/
1274struct hpi_control {
1275 u32 h_control;
1276 u16 control_type;
1277 u16 src_node_type;
1278 u16 src_node_index;
1279 u16 dst_node_type;
1280 u16 dst_node_index;
1281 u16 band;
1282 char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
1283};
1284
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001285static const char * const asihpi_tuner_band_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001286 "invalid",
1287 "AM",
1288 "FM mono",
1289 "TV NTSC-M",
1290 "FM stereo",
1291 "AUX",
1292 "TV PAL BG",
1293 "TV PAL I",
1294 "TV PAL DK",
1295 "TV SECAM",
1296};
1297
1298compile_time_assert(
1299 (ARRAY_SIZE(asihpi_tuner_band_names) ==
1300 (HPI_TUNER_BAND_LAST+1)),
1301 assert_tuner_band_names_size);
1302
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001303static const char * const asihpi_src_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001304 "no source",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001305 "PCM",
1306 "Line",
1307 "Digital",
1308 "Tuner",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001309 "RF",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001310 "Clock",
1311 "Bitstream",
Eliot Blennerhassettc8306132011-07-22 15:53:00 +12001312 "Mic",
1313 "Net",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001314 "Analog",
1315 "Adapter",
Eliot Blennerhassettc8306132011-07-22 15:53:00 +12001316 "RTP",
1317 "GPI",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001318};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001319
1320compile_time_assert(
1321 (ARRAY_SIZE(asihpi_src_names) ==
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12001322 (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001323 assert_src_names_size);
1324
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001325static const char * const asihpi_dst_names[] = {
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001326 "no destination",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001327 "PCM",
1328 "Line",
1329 "Digital",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001330 "RF",
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001331 "Speaker",
Eliot Blennerhassettc8306132011-07-22 15:53:00 +12001332 "Net",
1333 "Analog",
1334 "RTP",
1335 "GPO",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001336};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001337
1338compile_time_assert(
1339 (ARRAY_SIZE(asihpi_dst_names) ==
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12001340 (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001341 assert_dst_names_size);
1342
1343static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
1344 struct snd_card_asihpi *asihpi)
1345{
1346 int err;
1347
1348 err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi));
1349 if (err < 0)
1350 return err;
1351 else if (mixer_dump)
1352 snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index);
1353
1354 return 0;
1355}
1356
1357/* Convert HPI control name and location into ALSA control name */
1358static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
1359 struct hpi_control *hpi_ctl,
1360 char *name)
1361{
Eliot Blennerhassett550ac6b2011-04-05 20:55:41 +12001362 char *dir;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001363 memset(snd_control, 0, sizeof(*snd_control));
1364 snd_control->name = hpi_ctl->name;
1365 snd_control->private_value = hpi_ctl->h_control;
1366 snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1367 snd_control->index = 0;
1368
Eliot Blennerhassett550ac6b2011-04-05 20:55:41 +12001369 if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE)
1370 dir = ""; /* clock is neither capture nor playback */
1371 else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001372 dir = "Capture "; /* On or towards a PCM capture destination*/
1373 else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1374 (!hpi_ctl->dst_node_type))
1375 dir = "Capture "; /* On a source node that is not PCM playback */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001376 else if (hpi_ctl->src_node_type &&
1377 (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001378 (hpi_ctl->dst_node_type))
1379 dir = "Monitor Playback "; /* Between an input and an output */
1380 else
1381 dir = "Playback "; /* PCM Playback source, or output node */
1382
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001383 if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
Eliot Blennerhassett550ac6b2011-04-05 20:55:41 +12001384 sprintf(hpi_ctl->name, "%s %d %s %d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001385 asihpi_src_names[hpi_ctl->src_node_type],
1386 hpi_ctl->src_node_index,
1387 asihpi_dst_names[hpi_ctl->dst_node_type],
1388 hpi_ctl->dst_node_index,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001389 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001390 else if (hpi_ctl->dst_node_type) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001391 sprintf(hpi_ctl->name, "%s %d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001392 asihpi_dst_names[hpi_ctl->dst_node_type],
1393 hpi_ctl->dst_node_index,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001394 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001395 } else {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001396 sprintf(hpi_ctl->name, "%s %d %s%s",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001397 asihpi_src_names[hpi_ctl->src_node_type],
1398 hpi_ctl->src_node_index,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001399 dir, name);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001400 }
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001401 /* printk(KERN_INFO "Adding %s %d to %d ", hpi_ctl->name,
1402 hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001403}
1404
1405/*------------------------------------------------------------
1406 Volume controls
1407 ------------------------------------------------------------*/
1408#define VOL_STEP_mB 1
1409static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
1410 struct snd_ctl_elem_info *uinfo)
1411{
1412 u32 h_control = kcontrol->private_value;
1413 u16 err;
1414 /* native gains are in millibels */
1415 short min_gain_mB;
1416 short max_gain_mB;
1417 short step_gain_mB;
1418
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001419 err = hpi_volume_query_range(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001420 &min_gain_mB, &max_gain_mB, &step_gain_mB);
1421 if (err) {
1422 max_gain_mB = 0;
1423 min_gain_mB = -10000;
1424 step_gain_mB = VOL_STEP_mB;
1425 }
1426
1427 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1428 uinfo->count = 2;
1429 uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;
1430 uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;
1431 uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;
1432 return 0;
1433}
1434
1435static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
1436 struct snd_ctl_elem_value *ucontrol)
1437{
1438 u32 h_control = kcontrol->private_value;
1439 short an_gain_mB[HPI_MAX_CHANNELS];
1440
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001441 hpi_handle_error(hpi_volume_get_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001442 ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;
1443 ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;
1444
1445 return 0;
1446}
1447
1448static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
1449 struct snd_ctl_elem_value *ucontrol)
1450{
1451 int change;
1452 u32 h_control = kcontrol->private_value;
1453 short an_gain_mB[HPI_MAX_CHANNELS];
1454
1455 an_gain_mB[0] =
1456 (ucontrol->value.integer.value[0]) * VOL_STEP_mB;
1457 an_gain_mB[1] =
1458 (ucontrol->value.integer.value[1]) * VOL_STEP_mB;
1459 /* change = asihpi->mixer_volume[addr][0] != left ||
1460 asihpi->mixer_volume[addr][1] != right;
1461 */
1462 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001463 hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001464 return change;
1465}
1466
1467static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
1468
Takashi Iwai000477a2011-07-22 07:57:44 +02001469#define snd_asihpi_volume_mute_info snd_ctl_boolean_mono_info
Eliot Blennerhassettfe0aa88e2011-07-22 15:53:03 +12001470
1471static int snd_asihpi_volume_mute_get(struct snd_kcontrol *kcontrol,
1472 struct snd_ctl_elem_value *ucontrol)
1473{
1474 u32 h_control = kcontrol->private_value;
1475 u32 mute;
1476
1477 hpi_handle_error(hpi_volume_get_mute(h_control, &mute));
1478 ucontrol->value.integer.value[0] = mute ? 0 : 1;
1479
1480 return 0;
1481}
1482
1483static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol,
1484 struct snd_ctl_elem_value *ucontrol)
1485{
1486 u32 h_control = kcontrol->private_value;
1487 int change = 1;
1488 /* HPI currently only supports all or none muting of multichannel volume
1489 ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted
1490 */
1491 int mute = ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS;
1492 hpi_handle_error(hpi_volume_set_mute(h_control, mute));
1493 return change;
1494}
1495
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001496static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
1497 struct hpi_control *hpi_ctl)
1498{
1499 struct snd_card *card = asihpi->card;
1500 struct snd_kcontrol_new snd_control;
Eliot Blennerhassettfe0aa88e2011-07-22 15:53:03 +12001501 int err;
1502 u32 mute;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001503
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001504 asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001505 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1506 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1507 snd_control.info = snd_asihpi_volume_info;
1508 snd_control.get = snd_asihpi_volume_get;
1509 snd_control.put = snd_asihpi_volume_put;
1510 snd_control.tlv.p = db_scale_100;
1511
Eliot Blennerhassettfe0aa88e2011-07-22 15:53:03 +12001512 err = ctl_add(card, &snd_control, asihpi);
1513 if (err)
1514 return err;
1515
1516 if (hpi_volume_get_mute(hpi_ctl->h_control, &mute) == 0) {
1517 asihpi_ctl_init(&snd_control, hpi_ctl, "Switch");
1518 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1519 snd_control.info = snd_asihpi_volume_mute_info;
1520 snd_control.get = snd_asihpi_volume_mute_get;
1521 snd_control.put = snd_asihpi_volume_mute_put;
1522 err = ctl_add(card, &snd_control, asihpi);
1523 }
1524 return err;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001525}
1526
1527/*------------------------------------------------------------
1528 Level controls
1529 ------------------------------------------------------------*/
1530static int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,
1531 struct snd_ctl_elem_info *uinfo)
1532{
1533 u32 h_control = kcontrol->private_value;
1534 u16 err;
1535 short min_gain_mB;
1536 short max_gain_mB;
1537 short step_gain_mB;
1538
1539 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001540 hpi_level_query_range(h_control, &min_gain_mB,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001541 &max_gain_mB, &step_gain_mB);
1542 if (err) {
1543 max_gain_mB = 2400;
1544 min_gain_mB = -1000;
1545 step_gain_mB = 100;
1546 }
1547
1548 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1549 uinfo->count = 2;
1550 uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB;
1551 uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB;
1552 uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB;
1553 return 0;
1554}
1555
1556static int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,
1557 struct snd_ctl_elem_value *ucontrol)
1558{
1559 u32 h_control = kcontrol->private_value;
1560 short an_gain_mB[HPI_MAX_CHANNELS];
1561
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001562 hpi_handle_error(hpi_level_get_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001563 ucontrol->value.integer.value[0] =
1564 an_gain_mB[0] / HPI_UNITS_PER_dB;
1565 ucontrol->value.integer.value[1] =
1566 an_gain_mB[1] / HPI_UNITS_PER_dB;
1567
1568 return 0;
1569}
1570
1571static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,
1572 struct snd_ctl_elem_value *ucontrol)
1573{
1574 int change;
1575 u32 h_control = kcontrol->private_value;
1576 short an_gain_mB[HPI_MAX_CHANNELS];
1577
1578 an_gain_mB[0] =
1579 (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1580 an_gain_mB[1] =
1581 (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB;
1582 /* change = asihpi->mixer_level[addr][0] != left ||
1583 asihpi->mixer_level[addr][1] != right;
1584 */
1585 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001586 hpi_handle_error(hpi_level_set_gain(h_control, an_gain_mB));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001587 return change;
1588}
1589
1590static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0);
1591
1592static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
1593 struct hpi_control *hpi_ctl)
1594{
1595 struct snd_card *card = asihpi->card;
1596 struct snd_kcontrol_new snd_control;
1597
1598 /* can't use 'volume' cos some nodes have volume as well */
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001599 asihpi_ctl_init(&snd_control, hpi_ctl, "Level");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001600 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1601 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1602 snd_control.info = snd_asihpi_level_info;
1603 snd_control.get = snd_asihpi_level_get;
1604 snd_control.put = snd_asihpi_level_put;
1605 snd_control.tlv.p = db_scale_level;
1606
1607 return ctl_add(card, &snd_control, asihpi);
1608}
1609
1610/*------------------------------------------------------------
1611 AESEBU controls
1612 ------------------------------------------------------------*/
1613
1614/* AESEBU format */
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001615static const char * const asihpi_aesebu_format_names[] = {
1616 "N/A", "S/PDIF", "AES/EBU" };
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001617
1618static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
1619 struct snd_ctl_elem_info *uinfo)
1620{
1621 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1622 uinfo->count = 1;
1623 uinfo->value.enumerated.items = 3;
1624
1625 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1626 uinfo->value.enumerated.item =
1627 uinfo->value.enumerated.items - 1;
1628
1629 strcpy(uinfo->value.enumerated.name,
1630 asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
1631
1632 return 0;
1633}
1634
1635static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
1636 struct snd_ctl_elem_value *ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001637 u16 (*func)(u32, u16 *))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001638{
1639 u32 h_control = kcontrol->private_value;
1640 u16 source, err;
1641
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001642 err = func(h_control, &source);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001643
1644 /* default to N/A */
1645 ucontrol->value.enumerated.item[0] = 0;
1646 /* return success but set the control to N/A */
1647 if (err)
1648 return 0;
1649 if (source == HPI_AESEBU_FORMAT_SPDIF)
1650 ucontrol->value.enumerated.item[0] = 1;
1651 if (source == HPI_AESEBU_FORMAT_AESEBU)
1652 ucontrol->value.enumerated.item[0] = 2;
1653
1654 return 0;
1655}
1656
1657static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
1658 struct snd_ctl_elem_value *ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001659 u16 (*func)(u32, u16))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001660{
1661 u32 h_control = kcontrol->private_value;
1662
1663 /* default to S/PDIF */
1664 u16 source = HPI_AESEBU_FORMAT_SPDIF;
1665
1666 if (ucontrol->value.enumerated.item[0] == 1)
1667 source = HPI_AESEBU_FORMAT_SPDIF;
1668 if (ucontrol->value.enumerated.item[0] == 2)
1669 source = HPI_AESEBU_FORMAT_AESEBU;
1670
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001671 if (func(h_control, source) != 0)
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001672 return -EINVAL;
1673
1674 return 1;
1675}
1676
1677static int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,
1678 struct snd_ctl_elem_value *ucontrol) {
1679 return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001680 hpi_aesebu_receiver_get_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001681}
1682
1683static int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,
1684 struct snd_ctl_elem_value *ucontrol) {
1685 return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001686 hpi_aesebu_receiver_set_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001687}
1688
1689static int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol,
1690 struct snd_ctl_elem_info *uinfo)
1691{
1692 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1693 uinfo->count = 1;
1694
1695 uinfo->value.integer.min = 0;
1696 uinfo->value.integer.max = 0X1F;
1697 uinfo->value.integer.step = 1;
1698
1699 return 0;
1700}
1701
1702static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,
1703 struct snd_ctl_elem_value *ucontrol) {
1704
1705 u32 h_control = kcontrol->private_value;
1706 u16 status;
1707
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001708 hpi_handle_error(hpi_aesebu_receiver_get_error_status(
1709 h_control, &status));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001710 ucontrol->value.integer.value[0] = status;
1711 return 0;
1712}
1713
1714static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
1715 struct hpi_control *hpi_ctl)
1716{
1717 struct snd_card *card = asihpi->card;
1718 struct snd_kcontrol_new snd_control;
1719
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001720 asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001721 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1722 snd_control.info = snd_asihpi_aesebu_format_info;
1723 snd_control.get = snd_asihpi_aesebu_rx_format_get;
1724 snd_control.put = snd_asihpi_aesebu_rx_format_put;
1725
1726
1727 if (ctl_add(card, &snd_control, asihpi) < 0)
1728 return -EINVAL;
1729
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001730 asihpi_ctl_init(&snd_control, hpi_ctl, "Status");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001731 snd_control.access =
1732 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
1733 snd_control.info = snd_asihpi_aesebu_rxstatus_info;
1734 snd_control.get = snd_asihpi_aesebu_rxstatus_get;
1735
1736 return ctl_add(card, &snd_control, asihpi);
1737}
1738
1739static int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,
1740 struct snd_ctl_elem_value *ucontrol) {
1741 return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001742 hpi_aesebu_transmitter_get_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001743}
1744
1745static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,
1746 struct snd_ctl_elem_value *ucontrol) {
1747 return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001748 hpi_aesebu_transmitter_set_format);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001749}
1750
1751
1752static int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,
1753 struct hpi_control *hpi_ctl)
1754{
1755 struct snd_card *card = asihpi->card;
1756 struct snd_kcontrol_new snd_control;
1757
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13001758 asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001759 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1760 snd_control.info = snd_asihpi_aesebu_format_info;
1761 snd_control.get = snd_asihpi_aesebu_tx_format_get;
1762 snd_control.put = snd_asihpi_aesebu_tx_format_put;
1763
1764 return ctl_add(card, &snd_control, asihpi);
1765}
1766
1767/*------------------------------------------------------------
1768 Tuner controls
1769 ------------------------------------------------------------*/
1770
1771/* Gain */
1772
1773static int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,
1774 struct snd_ctl_elem_info *uinfo)
1775{
1776 u32 h_control = kcontrol->private_value;
1777 u16 err;
1778 short idx;
1779 u16 gain_range[3];
1780
1781 for (idx = 0; idx < 3; idx++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001782 err = hpi_tuner_query_gain(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001783 idx, &gain_range[idx]);
1784 if (err != 0)
1785 return err;
1786 }
1787
1788 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1789 uinfo->count = 1;
1790 uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB;
1791 uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB;
1792 uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB;
1793 return 0;
1794}
1795
1796static int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,
1797 struct snd_ctl_elem_value *ucontrol)
1798{
1799 /*
1800 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1801 */
1802 u32 h_control = kcontrol->private_value;
1803 short gain;
1804
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001805 hpi_handle_error(hpi_tuner_get_gain(h_control, &gain));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001806 ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
1807
1808 return 0;
1809}
1810
1811static int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,
1812 struct snd_ctl_elem_value *ucontrol)
1813{
1814 /*
1815 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1816 */
1817 u32 h_control = kcontrol->private_value;
1818 short gain;
1819
1820 gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001821 hpi_handle_error(hpi_tuner_set_gain(h_control, gain));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001822
1823 return 1;
1824}
1825
1826/* Band */
1827
1828static int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,
1829 u16 *band_list, u32 len) {
1830 u32 h_control = kcontrol->private_value;
1831 u16 err = 0;
1832 u32 i;
1833
1834 for (i = 0; i < len; i++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001835 err = hpi_tuner_query_band(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001836 h_control, i, &band_list[i]);
1837 if (err != 0)
1838 break;
1839 }
1840
1841 if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX))
1842 return -EIO;
1843
1844 return i;
1845}
1846
1847static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
1848 struct snd_ctl_elem_info *uinfo)
1849{
1850 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1851 int num_bands = 0;
1852
1853 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1854 HPI_TUNER_BAND_LAST);
1855
1856 if (num_bands < 0)
1857 return num_bands;
1858
1859 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1860 uinfo->count = 1;
1861 uinfo->value.enumerated.items = num_bands;
1862
1863 if (num_bands > 0) {
1864 if (uinfo->value.enumerated.item >=
1865 uinfo->value.enumerated.items)
1866 uinfo->value.enumerated.item =
1867 uinfo->value.enumerated.items - 1;
1868
1869 strcpy(uinfo->value.enumerated.name,
1870 asihpi_tuner_band_names[
1871 tuner_bands[uinfo->value.enumerated.item]]);
1872
1873 }
1874 return 0;
1875}
1876
1877static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
1878 struct snd_ctl_elem_value *ucontrol)
1879{
1880 u32 h_control = kcontrol->private_value;
1881 /*
1882 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1883 */
1884 u16 band, idx;
1885 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1886 u32 num_bands = 0;
1887
1888 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1889 HPI_TUNER_BAND_LAST);
1890
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001891 hpi_handle_error(hpi_tuner_get_band(h_control, &band));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001892
1893 ucontrol->value.enumerated.item[0] = -1;
1894 for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
1895 if (tuner_bands[idx] == band) {
1896 ucontrol->value.enumerated.item[0] = idx;
1897 break;
1898 }
1899
1900 return 0;
1901}
1902
1903static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
1904 struct snd_ctl_elem_value *ucontrol)
1905{
1906 /*
1907 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1908 */
1909 u32 h_control = kcontrol->private_value;
1910 u16 band;
1911 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1912 u32 num_bands = 0;
1913
1914 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1915 HPI_TUNER_BAND_LAST);
1916
1917 band = tuner_bands[ucontrol->value.enumerated.item[0]];
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001918 hpi_handle_error(hpi_tuner_set_band(h_control, band));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001919
1920 return 1;
1921}
1922
1923/* Freq */
1924
1925static int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,
1926 struct snd_ctl_elem_info *uinfo)
1927{
1928 u32 h_control = kcontrol->private_value;
1929 u16 err;
1930 u16 tuner_bands[HPI_TUNER_BAND_LAST];
1931 u16 num_bands = 0, band_iter, idx;
1932 u32 freq_range[3], temp_freq_range[3];
1933
1934 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1935 HPI_TUNER_BAND_LAST);
1936
1937 freq_range[0] = INT_MAX;
1938 freq_range[1] = 0;
1939 freq_range[2] = INT_MAX;
1940
1941 for (band_iter = 0; band_iter < num_bands; band_iter++) {
1942 for (idx = 0; idx < 3; idx++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001943 err = hpi_tuner_query_frequency(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001944 idx, tuner_bands[band_iter],
1945 &temp_freq_range[idx]);
1946 if (err != 0)
1947 return err;
1948 }
1949
1950 /* skip band with bogus stepping */
1951 if (temp_freq_range[2] <= 0)
1952 continue;
1953
1954 if (temp_freq_range[0] < freq_range[0])
1955 freq_range[0] = temp_freq_range[0];
1956 if (temp_freq_range[1] > freq_range[1])
1957 freq_range[1] = temp_freq_range[1];
1958 if (temp_freq_range[2] < freq_range[2])
1959 freq_range[2] = temp_freq_range[2];
1960 }
1961
1962 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1963 uinfo->count = 1;
1964 uinfo->value.integer.min = ((int)freq_range[0]);
1965 uinfo->value.integer.max = ((int)freq_range[1]);
1966 uinfo->value.integer.step = ((int)freq_range[2]);
1967 return 0;
1968}
1969
1970static int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,
1971 struct snd_ctl_elem_value *ucontrol)
1972{
1973 u32 h_control = kcontrol->private_value;
1974 u32 freq;
1975
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001976 hpi_handle_error(hpi_tuner_get_frequency(h_control, &freq));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001977 ucontrol->value.integer.value[0] = freq;
1978
1979 return 0;
1980}
1981
1982static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,
1983 struct snd_ctl_elem_value *ucontrol)
1984{
1985 u32 h_control = kcontrol->private_value;
1986 u32 freq;
1987
1988 freq = ucontrol->value.integer.value[0];
Eliot Blennerhassettba944552011-02-10 17:26:04 +13001989 hpi_handle_error(hpi_tuner_set_frequency(h_control, freq));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02001990
1991 return 1;
1992}
1993
1994/* Tuner control group initializer */
1995static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
1996 struct hpi_control *hpi_ctl)
1997{
1998 struct snd_card *card = asihpi->card;
1999 struct snd_kcontrol_new snd_control;
2000
2001 snd_control.private_value = hpi_ctl->h_control;
2002 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2003
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002004 if (!hpi_tuner_get_gain(hpi_ctl->h_control, NULL)) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002005 asihpi_ctl_init(&snd_control, hpi_ctl, "Gain");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002006 snd_control.info = snd_asihpi_tuner_gain_info;
2007 snd_control.get = snd_asihpi_tuner_gain_get;
2008 snd_control.put = snd_asihpi_tuner_gain_put;
2009
2010 if (ctl_add(card, &snd_control, asihpi) < 0)
2011 return -EINVAL;
2012 }
2013
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002014 asihpi_ctl_init(&snd_control, hpi_ctl, "Band");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002015 snd_control.info = snd_asihpi_tuner_band_info;
2016 snd_control.get = snd_asihpi_tuner_band_get;
2017 snd_control.put = snd_asihpi_tuner_band_put;
2018
2019 if (ctl_add(card, &snd_control, asihpi) < 0)
2020 return -EINVAL;
2021
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002022 asihpi_ctl_init(&snd_control, hpi_ctl, "Freq");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002023 snd_control.info = snd_asihpi_tuner_freq_info;
2024 snd_control.get = snd_asihpi_tuner_freq_get;
2025 snd_control.put = snd_asihpi_tuner_freq_put;
2026
2027 return ctl_add(card, &snd_control, asihpi);
2028}
2029
2030/*------------------------------------------------------------
2031 Meter controls
2032 ------------------------------------------------------------*/
2033static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,
2034 struct snd_ctl_elem_info *uinfo)
2035{
2036 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2037 uinfo->count = HPI_MAX_CHANNELS;
2038 uinfo->value.integer.min = 0;
2039 uinfo->value.integer.max = 0x7FFFFFFF;
2040 return 0;
2041}
2042
2043/* linear values for 10dB steps */
2044static int log2lin[] = {
2045 0x7FFFFFFF, /* 0dB */
2046 679093956,
2047 214748365,
2048 67909396,
2049 21474837,
2050 6790940,
2051 2147484, /* -60dB */
2052 679094,
2053 214748, /* -80 */
2054 67909,
2055 21475, /* -100 */
2056 6791,
2057 2147,
2058 679,
2059 214,
2060 68,
2061 21,
2062 7,
2063 2
2064};
2065
2066static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,
2067 struct snd_ctl_elem_value *ucontrol)
2068{
2069 u32 h_control = kcontrol->private_value;
2070 short an_gain_mB[HPI_MAX_CHANNELS], i;
2071 u16 err;
2072
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002073 err = hpi_meter_get_peak(h_control, an_gain_mB);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002074
2075 for (i = 0; i < HPI_MAX_CHANNELS; i++) {
2076 if (err) {
2077 ucontrol->value.integer.value[i] = 0;
2078 } else if (an_gain_mB[i] >= 0) {
2079 ucontrol->value.integer.value[i] =
2080 an_gain_mB[i] << 16;
2081 } else {
2082 /* -ve is log value in millibels < -60dB,
2083 * convert to (roughly!) linear,
2084 */
2085 ucontrol->value.integer.value[i] =
2086 log2lin[an_gain_mB[i] / -1000];
2087 }
2088 }
2089 return 0;
2090}
2091
2092static int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,
2093 struct hpi_control *hpi_ctl, int subidx)
2094{
2095 struct snd_card *card = asihpi->card;
2096 struct snd_kcontrol_new snd_control;
2097
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002098 asihpi_ctl_init(&snd_control, hpi_ctl, "Meter");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002099 snd_control.access =
2100 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2101 snd_control.info = snd_asihpi_meter_info;
2102 snd_control.get = snd_asihpi_meter_get;
2103
2104 snd_control.index = subidx;
2105
2106 return ctl_add(card, &snd_control, asihpi);
2107}
2108
2109/*------------------------------------------------------------
2110 Multiplexer controls
2111 ------------------------------------------------------------*/
2112static int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)
2113{
2114 u32 h_control = snd_control->private_value;
2115 struct hpi_control hpi_ctl;
2116 int s, err;
2117 for (s = 0; s < 32; s++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002118 err = hpi_multiplexer_query_source(h_control, s,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002119 &hpi_ctl.
2120 src_node_type,
2121 &hpi_ctl.
2122 src_node_index);
2123 if (err)
2124 break;
2125 }
2126 return s;
2127}
2128
2129static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
2130 struct snd_ctl_elem_info *uinfo)
2131{
2132 int err;
2133 u16 src_node_type, src_node_index;
2134 u32 h_control = kcontrol->private_value;
2135
2136 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2137 uinfo->count = 1;
2138 uinfo->value.enumerated.items =
2139 snd_card_asihpi_mux_count_sources(kcontrol);
2140
2141 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2142 uinfo->value.enumerated.item =
2143 uinfo->value.enumerated.items - 1;
2144
2145 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002146 hpi_multiplexer_query_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002147 uinfo->value.enumerated.item,
2148 &src_node_type, &src_node_index);
2149
2150 sprintf(uinfo->value.enumerated.name, "%s %d",
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12002151 asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002152 src_node_index);
2153 return 0;
2154}
2155
2156static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
2157 struct snd_ctl_elem_value *ucontrol)
2158{
2159 u32 h_control = kcontrol->private_value;
2160 u16 source_type, source_index;
2161 u16 src_node_type, src_node_index;
2162 int s;
2163
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002164 hpi_handle_error(hpi_multiplexer_get_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002165 &source_type, &source_index));
2166 /* Should cache this search result! */
2167 for (s = 0; s < 256; s++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002168 if (hpi_multiplexer_query_source(h_control, s,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002169 &src_node_type, &src_node_index))
2170 break;
2171
2172 if ((source_type == src_node_type)
2173 && (source_index == src_node_index)) {
2174 ucontrol->value.enumerated.item[0] = s;
2175 return 0;
2176 }
2177 }
2178 snd_printd(KERN_WARNING
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002179 "Control %x failed to match mux source %hu %hu\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002180 h_control, source_type, source_index);
2181 ucontrol->value.enumerated.item[0] = 0;
2182 return 0;
2183}
2184
2185static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,
2186 struct snd_ctl_elem_value *ucontrol)
2187{
2188 int change;
2189 u32 h_control = kcontrol->private_value;
2190 u16 source_type, source_index;
2191 u16 e;
2192
2193 change = 1;
2194
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002195 e = hpi_multiplexer_query_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002196 ucontrol->value.enumerated.item[0],
2197 &source_type, &source_index);
2198 if (!e)
2199 hpi_handle_error(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002200 hpi_multiplexer_set_source(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002201 source_type, source_index));
2202 return change;
2203}
2204
2205
2206static int __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
2207 struct hpi_control *hpi_ctl)
2208{
2209 struct snd_card *card = asihpi->card;
2210 struct snd_kcontrol_new snd_control;
2211
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002212 asihpi_ctl_init(&snd_control, hpi_ctl, "Route");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002213 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2214 snd_control.info = snd_asihpi_mux_info;
2215 snd_control.get = snd_asihpi_mux_get;
2216 snd_control.put = snd_asihpi_mux_put;
2217
2218 return ctl_add(card, &snd_control, asihpi);
2219
2220}
2221
2222/*------------------------------------------------------------
2223 Channel mode controls
2224 ------------------------------------------------------------*/
2225static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
2226 struct snd_ctl_elem_info *uinfo)
2227{
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002228 static const char * const mode_names[HPI_CHANNEL_MODE_LAST + 1] = {
2229 "invalid",
2230 "Normal", "Swap",
2231 "From Left", "From Right",
2232 "To Left", "To Right"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002233 };
2234
2235 u32 h_control = kcontrol->private_value;
2236 u16 mode;
2237 int i;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002238 u16 mode_map[6];
2239 int valid_modes = 0;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002240
2241 /* HPI channel mode values can be from 1 to 6
2242 Some adapters only support a contiguous subset
2243 */
2244 for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002245 if (!hpi_channel_mode_query_mode(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002246 h_control, i, &mode)) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002247 mode_map[valid_modes] = mode;
2248 valid_modes++;
2249 }
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002250
2251 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2252 uinfo->count = 1;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002253 uinfo->value.enumerated.items = valid_modes;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002254
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002255 if (uinfo->value.enumerated.item >= valid_modes)
2256 uinfo->value.enumerated.item = valid_modes - 1;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002257
2258 strcpy(uinfo->value.enumerated.name,
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002259 mode_names[mode_map[uinfo->value.enumerated.item]]);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002260
2261 return 0;
2262}
2263
2264static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
2265 struct snd_ctl_elem_value *ucontrol)
2266{
2267 u32 h_control = kcontrol->private_value;
2268 u16 mode;
2269
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002270 if (hpi_channel_mode_get(h_control, &mode))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002271 mode = 1;
2272
2273 ucontrol->value.enumerated.item[0] = mode - 1;
2274
2275 return 0;
2276}
2277
2278static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,
2279 struct snd_ctl_elem_value *ucontrol)
2280{
2281 int change;
2282 u32 h_control = kcontrol->private_value;
2283
2284 change = 1;
2285
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002286 hpi_handle_error(hpi_channel_mode_set(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002287 ucontrol->value.enumerated.item[0] + 1));
2288 return change;
2289}
2290
2291
2292static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
2293 struct hpi_control *hpi_ctl)
2294{
2295 struct snd_card *card = asihpi->card;
2296 struct snd_kcontrol_new snd_control;
2297
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002298 asihpi_ctl_init(&snd_control, hpi_ctl, "Mode");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002299 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2300 snd_control.info = snd_asihpi_cmode_info;
2301 snd_control.get = snd_asihpi_cmode_get;
2302 snd_control.put = snd_asihpi_cmode_put;
2303
2304 return ctl_add(card, &snd_control, asihpi);
2305}
2306
2307/*------------------------------------------------------------
2308 Sampleclock source controls
2309 ------------------------------------------------------------*/
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002310static char *sampleclock_sources[MAX_CLOCKSOURCES] = {
2311 "N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
2312 "SMPTE", "Digital1", "Auto", "Network", "Invalid",
2313 "Prev Module",
2314 "Digital2", "Digital3", "Digital4", "Digital5",
2315 "Digital6", "Digital7", "Digital8"};
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002316
2317static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
2318 struct snd_ctl_elem_info *uinfo)
2319{
2320 struct snd_card_asihpi *asihpi =
2321 (struct snd_card_asihpi *)(kcontrol->private_data);
2322 struct clk_cache *clkcache = &asihpi->cc;
2323 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2324 uinfo->count = 1;
2325 uinfo->value.enumerated.items = clkcache->count;
2326
2327 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2328 uinfo->value.enumerated.item =
2329 uinfo->value.enumerated.items - 1;
2330
2331 strcpy(uinfo->value.enumerated.name,
2332 clkcache->s[uinfo->value.enumerated.item].name);
2333 return 0;
2334}
2335
2336static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
2337 struct snd_ctl_elem_value *ucontrol)
2338{
2339 struct snd_card_asihpi *asihpi =
2340 (struct snd_card_asihpi *)(kcontrol->private_data);
2341 struct clk_cache *clkcache = &asihpi->cc;
2342 u32 h_control = kcontrol->private_value;
2343 u16 source, srcindex = 0;
2344 int i;
2345
2346 ucontrol->value.enumerated.item[0] = 0;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002347 if (hpi_sample_clock_get_source(h_control, &source))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002348 source = 0;
2349
2350 if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002351 if (hpi_sample_clock_get_source_index(h_control, &srcindex))
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002352 srcindex = 0;
2353
2354 for (i = 0; i < clkcache->count; i++)
2355 if ((clkcache->s[i].source == source) &&
2356 (clkcache->s[i].index == srcindex))
2357 break;
2358
2359 ucontrol->value.enumerated.item[0] = i;
2360
2361 return 0;
2362}
2363
2364static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
2365 struct snd_ctl_elem_value *ucontrol)
2366{
2367 struct snd_card_asihpi *asihpi =
2368 (struct snd_card_asihpi *)(kcontrol->private_data);
2369 struct clk_cache *clkcache = &asihpi->cc;
2370 int change, item;
2371 u32 h_control = kcontrol->private_value;
2372
2373 change = 1;
2374 item = ucontrol->value.enumerated.item[0];
2375 if (item >= clkcache->count)
2376 item = clkcache->count-1;
2377
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002378 hpi_handle_error(hpi_sample_clock_set_source(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002379 h_control, clkcache->s[item].source));
2380
2381 if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002382 hpi_handle_error(hpi_sample_clock_set_source_index(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002383 h_control, clkcache->s[item].index));
2384 return change;
2385}
2386
2387/*------------------------------------------------------------
2388 Clkrate controls
2389 ------------------------------------------------------------*/
2390/* Need to change this to enumerated control with list of rates */
2391static int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol,
2392 struct snd_ctl_elem_info *uinfo)
2393{
2394 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2395 uinfo->count = 1;
2396 uinfo->value.integer.min = 8000;
2397 uinfo->value.integer.max = 192000;
2398 uinfo->value.integer.step = 100;
2399
2400 return 0;
2401}
2402
2403static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,
2404 struct snd_ctl_elem_value *ucontrol)
2405{
2406 u32 h_control = kcontrol->private_value;
2407 u32 rate;
2408 u16 e;
2409
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002410 e = hpi_sample_clock_get_local_rate(h_control, &rate);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002411 if (!e)
2412 ucontrol->value.integer.value[0] = rate;
2413 else
2414 ucontrol->value.integer.value[0] = 0;
2415 return 0;
2416}
2417
2418static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,
2419 struct snd_ctl_elem_value *ucontrol)
2420{
2421 int change;
2422 u32 h_control = kcontrol->private_value;
2423
2424 /* change = asihpi->mixer_clkrate[addr][0] != left ||
2425 asihpi->mixer_clkrate[addr][1] != right;
2426 */
2427 change = 1;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002428 hpi_handle_error(hpi_sample_clock_set_local_rate(h_control,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002429 ucontrol->value.integer.value[0]));
2430 return change;
2431}
2432
2433static int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol,
2434 struct snd_ctl_elem_info *uinfo)
2435{
2436 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2437 uinfo->count = 1;
2438 uinfo->value.integer.min = 8000;
2439 uinfo->value.integer.max = 192000;
2440 uinfo->value.integer.step = 100;
2441
2442 return 0;
2443}
2444
2445static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
2446 struct snd_ctl_elem_value *ucontrol)
2447{
2448 u32 h_control = kcontrol->private_value;
2449 u32 rate;
2450 u16 e;
2451
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002452 e = hpi_sample_clock_get_sample_rate(h_control, &rate);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002453 if (!e)
2454 ucontrol->value.integer.value[0] = rate;
2455 else
2456 ucontrol->value.integer.value[0] = 0;
2457 return 0;
2458}
2459
2460static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
2461 struct hpi_control *hpi_ctl)
2462{
2463 struct snd_card *card = asihpi->card;
2464 struct snd_kcontrol_new snd_control;
2465
2466 struct clk_cache *clkcache = &asihpi->cc;
2467 u32 hSC = hpi_ctl->h_control;
2468 int has_aes_in = 0;
2469 int i, j;
2470 u16 source;
2471
2472 snd_control.private_value = hpi_ctl->h_control;
2473
2474 clkcache->has_local = 0;
2475
2476 for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002477 if (hpi_sample_clock_query_source(hSC,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002478 i, &source))
2479 break;
2480 clkcache->s[i].source = source;
2481 clkcache->s[i].index = 0;
2482 clkcache->s[i].name = sampleclock_sources[source];
2483 if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2484 has_aes_in = 1;
2485 if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL)
2486 clkcache->has_local = 1;
2487 }
2488 if (has_aes_in)
2489 /* already will have picked up index 0 above */
2490 for (j = 1; j < 8; j++) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002491 if (hpi_sample_clock_query_source_index(hSC,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002492 j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,
2493 &source))
2494 break;
2495 clkcache->s[i].source =
2496 HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT;
2497 clkcache->s[i].index = j;
2498 clkcache->s[i].name = sampleclock_sources[
2499 j+HPI_SAMPLECLOCK_SOURCE_LAST];
2500 i++;
2501 }
2502 clkcache->count = i;
2503
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002504 asihpi_ctl_init(&snd_control, hpi_ctl, "Source");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002505 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2506 snd_control.info = snd_asihpi_clksrc_info;
2507 snd_control.get = snd_asihpi_clksrc_get;
2508 snd_control.put = snd_asihpi_clksrc_put;
2509 if (ctl_add(card, &snd_control, asihpi) < 0)
2510 return -EINVAL;
2511
2512
2513 if (clkcache->has_local) {
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002514 asihpi_ctl_init(&snd_control, hpi_ctl, "Localrate");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002515 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2516 snd_control.info = snd_asihpi_clklocal_info;
2517 snd_control.get = snd_asihpi_clklocal_get;
2518 snd_control.put = snd_asihpi_clklocal_put;
2519
2520
2521 if (ctl_add(card, &snd_control, asihpi) < 0)
2522 return -EINVAL;
2523 }
2524
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002525 asihpi_ctl_init(&snd_control, hpi_ctl, "Rate");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002526 snd_control.access =
2527 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2528 snd_control.info = snd_asihpi_clkrate_info;
2529 snd_control.get = snd_asihpi_clkrate_get;
2530
2531 return ctl_add(card, &snd_control, asihpi);
2532}
2533/*------------------------------------------------------------
2534 Mixer
2535 ------------------------------------------------------------*/
2536
2537static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
2538{
2539 struct snd_card *card = asihpi->card;
2540 unsigned int idx = 0;
2541 unsigned int subindex = 0;
2542 int err;
2543 struct hpi_control hpi_ctl, prev_ctl;
2544
2545 if (snd_BUG_ON(!asihpi))
2546 return -EINVAL;
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002547 strcpy(card->mixername, "Asihpi Mixer");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002548
2549 err =
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002550 hpi_mixer_open(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002551 &asihpi->h_mixer);
2552 hpi_handle_error(err);
2553 if (err)
2554 return -err;
2555
Takashi Iwai21896bc2010-06-02 12:08:37 +02002556 memset(&prev_ctl, 0, sizeof(prev_ctl));
2557 prev_ctl.control_type = -1;
2558
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002559 for (idx = 0; idx < 2000; idx++) {
2560 err = hpi_mixer_get_control_by_index(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002561 asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002562 idx,
2563 &hpi_ctl.src_node_type,
2564 &hpi_ctl.src_node_index,
2565 &hpi_ctl.dst_node_type,
2566 &hpi_ctl.dst_node_index,
2567 &hpi_ctl.control_type,
2568 &hpi_ctl.h_control);
2569 if (err) {
2570 if (err == HPI_ERROR_CONTROL_DISABLED) {
2571 if (mixer_dump)
2572 snd_printk(KERN_INFO
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002573 "Disabled HPI Control(%d)\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002574 idx);
2575 continue;
2576 } else
2577 break;
2578
2579 }
2580
Eliot Blennerhassett168f1b02010-07-06 08:37:06 +12002581 hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;
2582 hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002583
2584 /* ASI50xx in SSX mode has multiple meters on the same node.
2585 Use subindex to create distinct ALSA controls
2586 for any duplicated controls.
2587 */
2588 if ((hpi_ctl.control_type == prev_ctl.control_type) &&
2589 (hpi_ctl.src_node_type == prev_ctl.src_node_type) &&
2590 (hpi_ctl.src_node_index == prev_ctl.src_node_index) &&
2591 (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) &&
2592 (hpi_ctl.dst_node_index == prev_ctl.dst_node_index))
2593 subindex++;
2594 else
2595 subindex = 0;
2596
2597 prev_ctl = hpi_ctl;
2598
2599 switch (hpi_ctl.control_type) {
2600 case HPI_CONTROL_VOLUME:
2601 err = snd_asihpi_volume_add(asihpi, &hpi_ctl);
2602 break;
2603 case HPI_CONTROL_LEVEL:
2604 err = snd_asihpi_level_add(asihpi, &hpi_ctl);
2605 break;
2606 case HPI_CONTROL_MULTIPLEXER:
2607 err = snd_asihpi_mux_add(asihpi, &hpi_ctl);
2608 break;
2609 case HPI_CONTROL_CHANNEL_MODE:
2610 err = snd_asihpi_cmode_add(asihpi, &hpi_ctl);
2611 break;
2612 case HPI_CONTROL_METER:
2613 err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex);
2614 break;
2615 case HPI_CONTROL_SAMPLECLOCK:
2616 err = snd_asihpi_sampleclock_add(
2617 asihpi, &hpi_ctl);
2618 break;
2619 case HPI_CONTROL_CONNECTION: /* ignore these */
2620 continue;
2621 case HPI_CONTROL_TUNER:
2622 err = snd_asihpi_tuner_add(asihpi, &hpi_ctl);
2623 break;
2624 case HPI_CONTROL_AESEBU_TRANSMITTER:
2625 err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl);
2626 break;
2627 case HPI_CONTROL_AESEBU_RECEIVER:
2628 err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl);
2629 break;
2630 case HPI_CONTROL_VOX:
2631 case HPI_CONTROL_BITSTREAM:
2632 case HPI_CONTROL_MICROPHONE:
2633 case HPI_CONTROL_PARAMETRIC_EQ:
2634 case HPI_CONTROL_COMPANDER:
2635 default:
2636 if (mixer_dump)
2637 snd_printk(KERN_INFO
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002638 "Untranslated HPI Control"
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002639 "(%d) %d %d %d %d %d\n",
2640 idx,
2641 hpi_ctl.control_type,
2642 hpi_ctl.src_node_type,
2643 hpi_ctl.src_node_index,
2644 hpi_ctl.dst_node_type,
2645 hpi_ctl.dst_node_index);
2646 continue;
2647 };
2648 if (err < 0)
2649 return err;
2650 }
2651 if (HPI_ERROR_INVALID_OBJ_INDEX != err)
2652 hpi_handle_error(err);
2653
2654 snd_printk(KERN_INFO "%d mixer controls found\n", idx);
2655
2656 return 0;
2657}
2658
2659/*------------------------------------------------------------
2660 /proc interface
2661 ------------------------------------------------------------*/
2662
2663static void
2664snd_asihpi_proc_read(struct snd_info_entry *entry,
2665 struct snd_info_buffer *buffer)
2666{
2667 struct snd_card_asihpi *asihpi = entry->private_data;
2668 u16 version;
2669 u32 h_control;
2670 u32 rate = 0;
2671 u16 source = 0;
2672 int err;
2673
2674 snd_iprintf(buffer, "ASIHPI driver proc file\n");
2675 snd_iprintf(buffer,
2676 "adapter ID=%4X\n_index=%d\n"
2677 "num_outstreams=%d\n_num_instreams=%d\n",
2678 asihpi->type, asihpi->adapter_index,
2679 asihpi->num_outstreams, asihpi->num_instreams);
2680
2681 version = asihpi->version;
2682 snd_iprintf(buffer,
2683 "serial#=%d\n_hw version %c%d\nDSP code version %03d\n",
2684 asihpi->serial_number, ((version >> 3) & 0xf) + 'A',
2685 version & 0x7,
2686 ((version >> 13) * 100) + ((version >> 7) & 0x3f));
2687
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002688 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002689 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2690 HPI_CONTROL_SAMPLECLOCK, &h_control);
2691
2692 if (!err) {
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002693 err = hpi_sample_clock_get_sample_rate(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002694 h_control, &rate);
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002695 err += hpi_sample_clock_get_source(h_control, &source);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002696
2697 if (!err)
2698 snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n",
2699 rate, sampleclock_sources[source]);
2700 }
2701
2702}
2703
2704
2705static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
2706{
2707 struct snd_info_entry *entry;
2708
2709 if (!snd_card_proc_new(asihpi->card, "info", &entry))
2710 snd_info_set_text_ops(entry, asihpi, snd_asihpi_proc_read);
2711}
2712
2713/*------------------------------------------------------------
2714 HWDEP
2715 ------------------------------------------------------------*/
2716
2717static int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file)
2718{
2719 if (enable_hpi_hwdep)
2720 return 0;
2721 else
2722 return -ENODEV;
2723
2724}
2725
2726static int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file)
2727{
2728 if (enable_hpi_hwdep)
2729 return asihpi_hpi_release(file);
2730 else
2731 return -ENODEV;
2732}
2733
2734static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
2735 unsigned int cmd, unsigned long arg)
2736{
2737 if (enable_hpi_hwdep)
2738 return asihpi_hpi_ioctl(file, cmd, arg);
2739 else
2740 return -ENODEV;
2741}
2742
2743
2744/* results in /dev/snd/hwC#D0 file for each card with index #
2745 also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
2746*/
2747static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
2748 int device, struct snd_hwdep **rhwdep)
2749{
2750 struct snd_hwdep *hw;
2751 int err;
2752
2753 if (rhwdep)
2754 *rhwdep = NULL;
2755 err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
2756 if (err < 0)
2757 return err;
2758 strcpy(hw->name, "asihpi (HPI)");
2759 hw->iface = SNDRV_HWDEP_IFACE_LAST;
2760 hw->ops.open = snd_asihpi_hpi_open;
2761 hw->ops.ioctl = snd_asihpi_hpi_ioctl;
2762 hw->ops.release = snd_asihpi_hpi_release;
2763 hw->private_data = asihpi;
2764 if (rhwdep)
2765 *rhwdep = hw;
2766 return 0;
2767}
2768
2769/*------------------------------------------------------------
2770 CARD
2771 ------------------------------------------------------------*/
2772static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
2773 const struct pci_device_id *pci_id)
2774{
2775 int err;
2776
2777 u16 version;
2778 int pcm_substreams;
2779
2780 struct hpi_adapter *hpi_card;
2781 struct snd_card *card;
2782 struct snd_card_asihpi *asihpi;
2783
2784 u32 h_control;
2785 u32 h_stream;
2786
2787 static int dev;
2788 if (dev >= SNDRV_CARDS)
2789 return -ENODEV;
2790
2791 /* Should this be enable[hpi_card->index] ? */
2792 if (!enable[dev]) {
2793 dev++;
2794 return -ENOENT;
2795 }
2796
2797 err = asihpi_adapter_probe(pci_dev, pci_id);
2798 if (err < 0)
2799 return err;
2800
2801 hpi_card = pci_get_drvdata(pci_dev);
2802 /* first try to give the card the same index as its hardware index */
2803 err = snd_card_create(hpi_card->index,
2804 id[hpi_card->index], THIS_MODULE,
2805 sizeof(struct snd_card_asihpi),
2806 &card);
2807 if (err < 0) {
2808 /* if that fails, try the default index==next available */
2809 err =
2810 snd_card_create(index[dev], id[dev],
2811 THIS_MODULE,
2812 sizeof(struct snd_card_asihpi),
2813 &card);
2814 if (err < 0)
2815 return err;
2816 snd_printk(KERN_WARNING
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002817 "**** WARNING **** Adapter index %d->ALSA index %d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002818 hpi_card->index, card->number);
2819 }
2820
Eliot Blennerhassett12253672011-02-10 17:26:10 +13002821 snd_card_set_dev(card, &pci_dev->dev);
2822
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002823 asihpi = (struct snd_card_asihpi *) card->private_data;
2824 asihpi->card = card;
Eliot Blennerhassett12253672011-02-10 17:26:10 +13002825 asihpi->pci = pci_dev;
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002826 asihpi->adapter_index = hpi_card->index;
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002827 hpi_handle_error(hpi_adapter_get_info(
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002828 asihpi->adapter_index,
2829 &asihpi->num_outstreams,
2830 &asihpi->num_instreams,
2831 &asihpi->version,
2832 &asihpi->serial_number, &asihpi->type));
2833
2834 version = asihpi->version;
2835 snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d "
2836 "num_instreams=%d S/N=%d\n"
Eliot Blennerhassette64b1a22011-02-10 17:25:59 +13002837 "Hw Version %c%d DSP code version %03d\n",
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002838 asihpi->type, asihpi->adapter_index,
2839 asihpi->num_outstreams,
2840 asihpi->num_instreams, asihpi->serial_number,
2841 ((version >> 3) & 0xf) + 'A',
2842 version & 0x7,
2843 ((version >> 13) * 100) + ((version >> 7) & 0x3f));
2844
2845 pcm_substreams = asihpi->num_outstreams;
2846 if (pcm_substreams < asihpi->num_instreams)
2847 pcm_substreams = asihpi->num_instreams;
2848
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002849 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002850 HPI_ADAPTER_PROPERTY_CAPS1,
2851 NULL, &asihpi->support_grouping);
2852 if (err)
2853 asihpi->support_grouping = 0;
2854
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002855 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002856 HPI_ADAPTER_PROPERTY_CAPS2,
2857 &asihpi->support_mrx, NULL);
2858 if (err)
2859 asihpi->support_mrx = 0;
2860
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002861 err = hpi_adapter_get_property(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002862 HPI_ADAPTER_PROPERTY_INTERVAL,
2863 NULL, &asihpi->update_interval_frames);
2864 if (err)
2865 asihpi->update_interval_frames = 512;
2866
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +12002867 if (!asihpi->can_dma)
Eliot Blennerhassett26aebef2011-03-25 15:25:47 +13002868 asihpi->update_interval_frames *= 2;
2869
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002870 hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002871 0, &h_stream));
2872
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002873 err = hpi_instream_host_buffer_free(h_stream);
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +12002874 asihpi->can_dma = (!err);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002875
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002876 hpi_handle_error(hpi_instream_close(h_stream));
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002877
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_CURCHANNELS,
2880 &asihpi->in_max_chans, &asihpi->out_max_chans);
2881 if (err) {
2882 asihpi->in_max_chans = 2;
2883 asihpi->out_max_chans = 2;
2884 }
2885
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +12002886 snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n",
2887 asihpi->can_dma,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002888 asihpi->support_grouping,
2889 asihpi->support_mrx
2890 );
2891
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002892 err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams);
2893 if (err < 0) {
2894 snd_printk(KERN_ERR "pcm_new failed\n");
2895 goto __nodev;
2896 }
2897 err = snd_card_asihpi_mixer_new(asihpi);
2898 if (err < 0) {
2899 snd_printk(KERN_ERR "mixer_new failed\n");
2900 goto __nodev;
2901 }
2902
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002903 err = hpi_mixer_get_control(asihpi->h_mixer,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002904 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2905 HPI_CONTROL_SAMPLECLOCK, &h_control);
2906
2907 if (!err)
2908 err = hpi_sample_clock_set_local_rate(
Eliot Blennerhassettba944552011-02-10 17:26:04 +13002909 h_control, adapter_fs);
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002910
2911 snd_asihpi_proc_init(asihpi);
2912
2913 /* always create, can be enabled or disabled dynamically
2914 by enable_hwdep module param*/
2915 snd_asihpi_hpi_new(asihpi, 0, NULL);
2916
Eliot Blennerhassettf3d145a2011-04-05 20:55:44 +12002917 strcpy(card->driver, "ASIHPI");
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002918
2919 sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
2920 sprintf(card->longname, "%s %i",
2921 card->shortname, asihpi->adapter_index);
2922 err = snd_card_register(card);
Eliot Blennerhassettb2e65c82011-03-25 15:25:48 +13002923
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002924 if (!err) {
2925 hpi_card->snd_card_asihpi = card;
2926 dev++;
2927 return 0;
2928 }
2929__nodev:
2930 snd_card_free(card);
2931 snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err);
2932 return err;
2933
2934}
2935
2936static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev)
2937{
2938 struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev);
2939
2940 snd_card_free(hpi_card->snd_card_asihpi);
2941 hpi_card->snd_card_asihpi = NULL;
2942 asihpi_adapter_remove(pci_dev);
2943}
2944
2945static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = {
2946 {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
2947 HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2948 (kernel_ulong_t)HPI_6205},
2949 {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
2950 HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2951 (kernel_ulong_t)HPI_6000},
2952 {0,}
2953};
2954MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
2955
2956static struct pci_driver driver = {
Takashi Iwai3733e422011-06-10 16:20:20 +02002957 .name = KBUILD_MODNAME,
Eliot Blennerhassett719f82d2010-04-21 18:17:39 +02002958 .id_table = asihpi_pci_tbl,
2959 .probe = snd_asihpi_probe,
2960 .remove = __devexit_p(snd_asihpi_remove),
2961#ifdef CONFIG_PM
2962/* .suspend = snd_asihpi_suspend,
2963 .resume = snd_asihpi_resume, */
2964#endif
2965};
2966
2967static int __init snd_asihpi_init(void)
2968{
2969 asihpi_init();
2970 return pci_register_driver(&driver);
2971}
2972
2973static void __exit snd_asihpi_exit(void)
2974{
2975
2976 pci_unregister_driver(&driver);
2977 asihpi_exit();
2978}
2979
2980module_init(snd_asihpi_init)
2981module_exit(snd_asihpi_exit)
2982