1719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*
2719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *  Asihpi soundcard
3719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *  Copyright (c) by AudioScience Inc <alsa@audioscience.com>
4719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *
5719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   This program is free software; you can redistribute it and/or modify
6719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   it under the terms of version 2 of the GNU General Public License as
7719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   published by the Free Software Foundation;
8719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *
9719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   This program is distributed in the hope that it will be useful,
10719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   GNU General Public License for more details.
13719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *
14719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   You should have received a copy of the GNU General Public License
15719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   along with this program; if not, write to the Free Software
16719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *
18719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *
19719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *  The following is not a condition of use, merely a request:
20719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *  If you modify this program, particularly if you fix errors, AudioScience Inc
21719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *  would appreciate it if you grant us the right to use those modifications
22719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett *  for any purpose including commercial applications.
23719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett */
24e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
25719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include "hpi_internal.h"
26719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include "hpimsginit.h"
27719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include "hpioctl.h"
28719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
29719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/pci.h>
30719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/init.h>
31719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/jiffies.h>
32719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/slab.h>
33719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/time.h>
34719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/wait.h>
35719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/core.h>
36719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/control.h>
37719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/pcm.h>
38719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/pcm_params.h>
39719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/info.h>
40719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/initval.h>
41719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/tlv.h>
42719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/hwdep.h>
43719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
44f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett
45719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_LICENSE("GPL");
46719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
47719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
48719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
49b0096a65677fa8d7e50975dc7282ce313610d9e8Eliot Blennerhassett#if defined CONFIG_SND_DEBUG
50a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett/* copied from pcm_lib.c, hope later patch will make that version public
51a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassettand this copy can be removed */
52a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassettstatic void pcm_debug_name(struct snd_pcm_substream *substream,
53a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett			   char *name, size_t len)
54a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett{
55a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snprintf(name, len, "pcmC%dD%d%c:%d",
56a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett		 substream->pcm->card->number,
57a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett		 substream->pcm->device,
58a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett		 substream->stream ? 'c' : 'p',
59a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett		 substream->number);
60a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett}
61a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name))
62b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett#else
63a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett#define pcm_debug_name(s, n, l) do { } while (0)
64a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett#define DEBUG_NAME(name, substream) do { } while (0)
65b0096a65677fa8d7e50975dc7282ce313610d9e8Eliot Blennerhassett#endif
66a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett
67b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett#if defined CONFIG_SND_DEBUG_VERBOSE
68b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett/**
69b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett * snd_printddd - very verbose debug printk
70b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett * @format: format string
71b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett *
72b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett * Works like snd_printk() for debugging purposes.
73b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set.
74b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett * Must set snd module debug parameter to 3 to enable at runtime.
75b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett */
76b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett#define snd_printddd(format, args...) \
77b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett	__snd_printk(3, __FILE__, __LINE__, format, ##args)
78b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett#else
79b0096a65677fa8d7e50975dc7282ce313610d9e8Eliot Blennerhassett#define snd_printddd(format, args...) do { } while (0)
80b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett#endif
81b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett
82719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* index 0-MAX */
83719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
84719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
85719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int enable_hpi_hwdep = 1;
86719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
87719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param_array(index, int, NULL, S_IRUGO);
88719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard.");
89719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
90719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param_array(id, charp, NULL, S_IRUGO);
91719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard.");
92719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
93719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param_array(enable, bool, NULL, S_IRUGO);
94719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard.");
95719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
96719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param(enable_hpi_hwdep, bool, S_IRUGO|S_IWUSR);
97719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(enable_hpi_hwdep,
98719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		"ALSA enable HPI hwdep for AudioScience soundcard ");
99719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
100719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* identify driver */
101719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#ifdef KERNEL_ALSA_BUILD
102e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettstatic char *build_info = "Built using headers from kernel source";
103719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param(build_info, charp, S_IRUGO);
104719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(build_info, "built using headers from kernel source");
105719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#else
106e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettstatic char *build_info = "Built within ALSA source";
107719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param(build_info, charp, S_IRUGO);
108719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(build_info, "built within ALSA source");
109719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
110719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
111719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* set to 1 to dump every control from adapter to log */
112719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic const int mixer_dump;
113719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
114719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define DEFAULT_SAMPLERATE 44100
115719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int adapter_fs = DEFAULT_SAMPLERATE;
116719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
117719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* defaults */
118719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define PERIODS_MIN 2
119e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett#define PERIOD_BYTES_MIN  2048
120719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define BUFFER_BYTES_MAX (512 * 1024)
121719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
122719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
123719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
124719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct clk_source {
125719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int source;
126719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int index;
127719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	char *name;
128719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
129719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
130719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct clk_cache {
131719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int count;
132719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int has_local;
133719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_source s[MAX_CLOCKSOURCES];
134719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
135719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
136719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Per card data */
137719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct snd_card_asihpi {
138719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card;
139719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct pci_dev *pci;
140719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 adapter_index;
141719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 serial_number;
142719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 type;
143719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 version;
144719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 num_outstreams;
145719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 num_instreams;
146719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
147719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_mixer;
148719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache cc;
149719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
150f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	u16 can_dma;
151719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 support_grouping;
152719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 support_mrx;
153719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 update_interval_frames;
154719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 in_max_chans;
155719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 out_max_chans;
156719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
157719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
158719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Per stream data */
159719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct snd_card_asihpi_pcm {
160719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct timer_list timer;
161719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int respawn_timer;
162719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int hpi_buffer_attached;
163ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	unsigned int buffer_bytes;
164ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	unsigned int period_bytes;
165719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int bytes_per_sec;
166e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
167e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	unsigned int pcm_buf_dma_ofs;	/* DMA R/W offset in buffer */
168e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	unsigned int pcm_buf_elapsed_dma_ofs;	/* DMA R/W offset in buffer */
1690b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett	unsigned int drained_count;
170719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_substream *substream;
171719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_stream;
172719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_format format;
173719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
174719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
175719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* universal stream verbs work with out or in stream handles */
176719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
177719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Functions to allow driver to give a buffer to HPI for busmastering */
178719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
179719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic u16 hpi_stream_host_buffer_attach(
180719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_stream,   /* handle to outstream. */
181719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 size_in_bytes, /* size in bytes of bus mastering buffer */
182719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 pci_address
183719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett)
184719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
185719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_message hm;
186719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_response hr;
187719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int obj = hpi_handle_object(h_stream);
188719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
189719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!h_stream)
190719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return HPI_ERROR_INVALID_OBJ;
191719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_init_message_response(&hm, &hr, obj,
192719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			obj == HPI_OBJ_OSTREAM ?
193719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_OSTREAM_HOSTBUFFER_ALLOC :
194719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_ISTREAM_HOSTBUFFER_ALLOC);
195719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
196719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_to_indexes(h_stream, &hm.adapter_index,
197719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hm.obj_index);
198719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
199719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hm.u.d.u.buffer.buffer_size = size_in_bytes;
200719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hm.u.d.u.buffer.pci_address = pci_address;
201719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER;
202719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_send_recv(&hm, &hr);
203719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return hr.error;
204719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
205719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
206ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic u16 hpi_stream_host_buffer_detach(u32  h_stream)
207719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
208719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_message hm;
209719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_response hr;
210719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int obj = hpi_handle_object(h_stream);
211719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
212719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!h_stream)
213719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return HPI_ERROR_INVALID_OBJ;
214719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
215719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_init_message_response(&hm, &hr,  obj,
216719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			obj == HPI_OBJ_OSTREAM ?
217719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_OSTREAM_HOSTBUFFER_FREE :
218719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_ISTREAM_HOSTBUFFER_FREE);
219719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
220719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_to_indexes(h_stream, &hm.adapter_index,
221719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hm.obj_index);
222719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER;
223719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_send_recv(&hm, &hr);
224719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return hr.error;
225719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
226719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
227ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_start(u32 h_stream)
228719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
229719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
230ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_start(h_stream);
231719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
232ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_start(h_stream);
233719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
234719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
235ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_stop(u32 h_stream)
236719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
237719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
238ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_stop(h_stream);
239719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
240ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_stop(h_stream);
241719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
242719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
243719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic inline u16 hpi_stream_get_info_ex(
244719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32 h_stream,
245719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u16        *pw_state,
246719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32        *pbuffer_size,
247719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32        *pdata_in_buffer,
248719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32        *psample_count,
249719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32        *pauxiliary_data
250719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett)
251719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
252e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	u16 e;
253719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream)  ==  HPI_OBJ_OSTREAM)
254ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		e = hpi_outstream_get_info_ex(h_stream, pw_state,
255719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					pbuffer_size, pdata_in_buffer,
256719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					psample_count, pauxiliary_data);
257719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
258ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		e = hpi_instream_get_info_ex(h_stream, pw_state,
259719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					pbuffer_size, pdata_in_buffer,
260719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					psample_count, pauxiliary_data);
261e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	return e;
262719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
263719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
264ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_group_add(
265719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					u32 h_master,
266719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					u32 h_stream)
267719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
268719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_master) ==  HPI_OBJ_OSTREAM)
269ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_group_add(h_master, h_stream);
270719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
271ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_group_add(h_master, h_stream);
272719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
273719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
274ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_group_reset(u32 h_stream)
275719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
276719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
277ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_group_reset(h_stream);
278719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
279ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_group_reset(h_stream);
280719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
281719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
282ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_group_get_map(
283719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				u32 h_stream, u32 *mo, u32 *mi)
284719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
285719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
286ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_group_get_map(h_stream, mo, mi);
287719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
288ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_group_get_map(h_stream, mo, mi);
289719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
290719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
291719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic u16 handle_error(u16 err, int line, char *filename)
292719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
293719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
294719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		printk(KERN_WARNING
295719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			"in file %s, line %d: HPI error %d\n",
296719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			filename, line, err);
297719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return err;
298719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
299719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
300719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define hpi_handle_error(x)  handle_error(x, __LINE__, __FILE__)
301719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
302719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/***************************** GENERAL PCM ****************/
303a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett
304a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassettstatic void print_hwparams(struct snd_pcm_substream *substream,
305a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett				struct snd_pcm_hw_params *p)
306719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
307a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	DEBUG_NAME(substream, name);
308a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd("%s HWPARAMS\n", name);
309a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" samplerate %d Hz\n", params_rate(p));
310a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" channels %d\n", params_channels(p));
311a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" format %d\n", params_format(p));
312a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" subformat %d\n", params_subformat(p));
313a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" buffer %d B\n", params_buffer_bytes(p));
314a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" period %d B\n", params_period_bytes(p));
315a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" access %d\n", params_access(p));
316a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" period_size %d\n", params_period_size(p));
317a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" periods %d\n", params_periods(p));
318a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" buffer_size %d\n", params_buffer_size(p));
319a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printd(" %d B/s\n", params_rate(p) *
320a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett		params_channels(p) *
321a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett		snd_pcm_format_width(params_format(p)) / 8);
322a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett
323719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
324719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
325719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic snd_pcm_format_t hpi_to_alsa_formats[] = {
326719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* INVALID */
327719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_U8,	/* HPI_FORMAT_PCM8_UNSIGNED        1 */
328719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_S16,	/* HPI_FORMAT_PCM16_SIGNED         2 */
329719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_MPEG_L1              3 */
330719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_MPEG,	/* HPI_FORMAT_MPEG_L2              4 */
331719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_MPEG,	/* HPI_FORMAT_MPEG_L3              5 */
332719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_DOLBY_AC2            6 */
333719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_DOLBY_AC3            7 */
334719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN      8 */
335719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_AA_TAGIT1_HITS       9 */
336719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_AA_TAGIT1_INSERTS   10 */
337719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_S32,	/* HPI_FORMAT_PCM32_SIGNED        11 */
338719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_RAW_BITSTREAM       12 */
339719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_AA_TAGIT1_HITS_EX1  13 */
340719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_FLOAT,	/* HPI_FORMAT_PCM32_FLOAT         14 */
341719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#if 1
342719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* ALSA can't handle 3 byte sample size together with power-of-2
343719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 *  constraint on buffer_bytes, so disable this format
344719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 */
345719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1
346719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#else
347ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	/* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */
348719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
349719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
350719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
351719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
352719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,
353719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					   u16 *hpi_format)
354719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
355719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 format;
356719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
357719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (format = HPI_FORMAT_PCM8_UNSIGNED;
358719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	     format <= HPI_FORMAT_PCM24_SIGNED; format++) {
359719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (hpi_to_alsa_formats[format] == alsa_format) {
360719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			*hpi_format = format;
361719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return 0;
362719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
363719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
364719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
365719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd(KERN_WARNING "failed match for alsa format %d\n",
366719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   alsa_format);
367719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*hpi_format = 0;
368719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return -EINVAL;
369719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
370719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
371719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
372719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					 struct snd_pcm_hardware *pcmhw)
373719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
374719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
375719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
376719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 sample_rate;
377719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int idx;
378719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int rate_min = 200000;
379719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int rate_max = 0;
380719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int rates = 0;
381719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
382719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (asihpi->support_mrx) {
383719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		rates |= SNDRV_PCM_RATE_CONTINUOUS;
384719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		rates |= SNDRV_PCM_RATE_8000_96000;
385719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		rate_min = 8000;
386719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		rate_max = 100000;
387719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	} else {
388719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* on cards without SRC,
389719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   valid rates are determined by sampleclock */
390ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_mixer_get_control(asihpi->h_mixer,
391719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
392719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					  HPI_CONTROL_SAMPLECLOCK, &h_control);
393719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err) {
394719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			snd_printk(KERN_ERR
395e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				"No local sampleclock, err %d\n", err);
396719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
397719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
3987bf76c33e9a1ecb2a15f1a066d4e032b5d0922a7Eliot Blennerhassett		for (idx = -1; idx < 100; idx++) {
3997bf76c33e9a1ecb2a15f1a066d4e032b5d0922a7Eliot Blennerhassett			if (idx == -1) {
4007bf76c33e9a1ecb2a15f1a066d4e032b5d0922a7Eliot Blennerhassett				if (hpi_sample_clock_get_sample_rate(h_control,
4017bf76c33e9a1ecb2a15f1a066d4e032b5d0922a7Eliot Blennerhassett								&sample_rate))
4027bf76c33e9a1ecb2a15f1a066d4e032b5d0922a7Eliot Blennerhassett					continue;
4037bf76c33e9a1ecb2a15f1a066d4e032b5d0922a7Eliot Blennerhassett			} else if (hpi_sample_clock_query_local_rate(h_control,
4047bf76c33e9a1ecb2a15f1a066d4e032b5d0922a7Eliot Blennerhassett							idx, &sample_rate)) {
405719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
406719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			}
407719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
408719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			rate_min = min(rate_min, sample_rate);
409719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			rate_max = max(rate_max, sample_rate);
410719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
411719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			switch (sample_rate) {
412719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 5512:
413719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_5512;
414719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
415719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 8000:
416719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_8000;
417719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
418719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 11025:
419719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_11025;
420719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
421719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 16000:
422719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_16000;
423719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
424719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 22050:
425719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_22050;
426719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
427719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 32000:
428719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_32000;
429719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
430719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 44100:
431719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_44100;
432719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
433719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 48000:
434719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_48000;
435719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
436719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 64000:
437719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_64000;
438719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
439719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 88200:
440719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_88200;
441719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
442719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 96000:
443719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_96000;
444719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
445719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 176400:
446719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_176400;
447719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
448719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 192000:
449719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_192000;
450719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
451719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			default: /* some other rate */
452719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_KNOT;
453719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			}
454719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
455719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
456719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
457719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcmhw->rates = rates;
458719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcmhw->rate_min = rate_min;
459719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcmhw->rate_max = rate_max;
460719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
461719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
462719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
463719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					 struct snd_pcm_hw_params *params)
464719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
465719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
466719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
467719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
468719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
469719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 format;
470315e8f7501ad929acacfa94c251283e837f281edKulikov Vasiliy	int width;
471719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int bytes_per_sec;
472719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
473a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	print_hwparams(substream, params);
474719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
475719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
476719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
477719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format);
478719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
479719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
480719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
481719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_error(hpi_format_create(&dpcm->format,
482719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			params_channels(params),
483719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			format, params_rate(params), 0, 0));
484719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
485719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
486ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (hpi_instream_reset(dpcm->h_stream) != 0)
487719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -EINVAL;
488719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
489ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (hpi_instream_set_format(
490719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			dpcm->h_stream, &dpcm->format) != 0)
491719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -EINVAL;
492719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
493719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
494719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->hpi_buffer_attached = 0;
495f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	if (card->can_dma) {
496ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_stream_host_buffer_attach(dpcm->h_stream,
497719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			params_buffer_bytes(params),  runtime->dma_addr);
498719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err == 0) {
499b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett			snd_printdd(
500719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				"stream_host_buffer_attach succeeded %u %lu\n",
501719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				params_buffer_bytes(params),
502719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				(unsigned long)runtime->dma_addr);
503719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		} else {
504b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett			snd_printd("stream_host_buffer_attach error %d\n",
505719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					err);
506719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -ENOMEM;
507719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
508719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
509ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
510719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						&dpcm->hpi_buffer_attached,
511719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						NULL, NULL, NULL);
512719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
513b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett		snd_printdd("stream_host_buffer_attach status 0x%x\n",
514719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				dpcm->hpi_buffer_attached);
515719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
516719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	bytes_per_sec = params_rate(params) * params_channels(params);
517315e8f7501ad929acacfa94c251283e837f281edKulikov Vasiliy	width = snd_pcm_format_width(params_format(params));
518315e8f7501ad929acacfa94c251283e837f281edKulikov Vasiliy	bytes_per_sec *= width;
519719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	bytes_per_sec /= 8;
520315e8f7501ad929acacfa94c251283e837f281edKulikov Vasiliy	if (width < 0 || bytes_per_sec == 0)
521719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
522719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
523719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->bytes_per_sec = bytes_per_sec;
524ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	dpcm->buffer_bytes = params_buffer_bytes(params);
525ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	dpcm->period_bytes = params_period_bytes(params);
526719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
527719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
528719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
529719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
530e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettstatic int
531e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettsnd_card_asihpi_hw_free(struct snd_pcm_substream *substream)
532e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett{
533e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
534e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
535e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	if (dpcm->hpi_buffer_attached)
536ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_stream_host_buffer_detach(dpcm->h_stream);
537e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
538e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	snd_pcm_lib_free_pages(substream);
539e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	return 0;
540e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett}
541e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
542e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettstatic void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)
543e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett{
544e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
545e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	kfree(dpcm);
546e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett}
547e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
548719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
549719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    substream)
550719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
551719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
552719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
553719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int expiry;
554719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
555ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	expiry = HZ / 200;
556ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	/*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */
557e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	expiry = max(expiry, 1); /* don't let it be zero! */
558719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.expires = jiffies + expiry;
559719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->respawn_timer = 1;
560719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	add_timer(&dpcm->timer);
561719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
562719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
563719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
564719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
565719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
566719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
567719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
568719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->respawn_timer = 0;
569719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	del_timer(&dpcm->timer);
570719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
571719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
572719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
573719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					   int cmd)
574719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
575719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
576719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
577719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_substream *s;
578719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 e;
579a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	DEBUG_NAME(substream, name);
580a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett
581a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printdd("%s trigger\n", name);
582719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
583719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	switch (cmd) {
584719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	case SNDRV_PCM_TRIGGER_START:
585719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_group_for_each_entry(s, substream) {
586e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			struct snd_pcm_runtime *runtime = s->runtime;
587e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			struct snd_card_asihpi_pcm *ds = runtime->private_data;
588719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
589719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (snd_pcm_substream_chip(s) != card)
590719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				continue;
591719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
592ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			/* don't link Cap and Play */
593ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (substream->stream != s->stream)
594ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				continue;
595ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
5960b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett			ds->drained_count = 0;
597f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
598719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				/* How do I know how much valid data is present
599e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				* in buffer? Must be at least one period!
600e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				* Guessing 2 periods, but if
601719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				* buffer is bigger it may contain even more
602719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				* data??
603719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				*/
604ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				unsigned int preload = ds->period_bytes * 1;
605b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett				snd_printddd("%d preload x%x\n", s->number, preload);
606719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				hpi_handle_error(hpi_outstream_write_buf(
607ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett						ds->h_stream,
608e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett						&runtime->dma_area[0],
609719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						preload,
610719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						&ds->format));
611e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				ds->pcm_buf_host_rw_ofs = preload;
612719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			}
613719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
614719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (card->support_grouping) {
615a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett				snd_printdd("%d group\n", s->number);
616ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				e = hpi_stream_group_add(
617719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					dpcm->h_stream,
618719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					ds->h_stream);
619719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				if (!e) {
620719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					snd_pcm_trigger_done(s, substream);
621719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				} else {
622719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_handle_error(e);
623719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					break;
624719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				}
625719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} else
626719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
627719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
628b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett		snd_printdd("start\n");
629719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* start the master stream */
630719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_pcm_timer_start(substream);
631c4ed97d9e7ec9b8c8453af4ce55497d85970426cEliot Blennerhassett		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
632f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			!card->can_dma)
633ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			hpi_handle_error(hpi_stream_start(dpcm->h_stream));
634719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		break;
635719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
636719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	case SNDRV_PCM_TRIGGER_STOP:
637719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_pcm_timer_stop(substream);
638719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_group_for_each_entry(s, substream) {
639719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (snd_pcm_substream_chip(s) != card)
640719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				continue;
641ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			/* don't link Cap and Play */
642ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (substream->stream != s->stream)
643ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				continue;
644719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
645719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			/*? workaround linked streams don't
646719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			transition to SETUP 20070706*/
647719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
648719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
649719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (card->support_grouping) {
650a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett				snd_printdd("%d group\n", s->number);
651719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				snd_pcm_trigger_done(s, substream);
652719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} else
653719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
654719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
655b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett		snd_printdd("stop\n");
656719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
657719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* _prepare and _hwparams reset the stream */
658ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
659719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
660719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			hpi_handle_error(
661ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				hpi_outstream_reset(dpcm->h_stream));
662719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
663719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (card->support_grouping)
664ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			hpi_handle_error(hpi_stream_group_reset(dpcm->h_stream));
665719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		break;
666719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
667719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
668b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett		snd_printdd("pause release\n");
669ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_stream_start(dpcm->h_stream));
670719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_pcm_timer_start(substream);
671719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		break;
672719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
673b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett		snd_printdd("pause\n");
674719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_pcm_timer_stop(substream);
675ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
676719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		break;
677719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	default:
678ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		snd_printd(KERN_ERR "\tINVALID\n");
679719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
680719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
681719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
682719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
683719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
684719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
685719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*algorithm outline
686719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett Without linking degenerates to getting single stream pos etc
687719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett Without mmap 2nd loop degenerates to snd_pcm_period_elapsed
688719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
689719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*
690e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettpcm_buf_dma_ofs=get_buf_pos(s);
691719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettfor_each_linked_stream(s) {
692e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	pcm_buf_dma_ofs=get_buf_pos(s);
693ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	min_buf_pos = modulo_min(min_buf_pos, pcm_buf_dma_ofs, buffer_bytes)
694e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	new_data = min(new_data, calc_new_data(pcm_buf_dma_ofs,irq_pos)
695719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
696719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassetttimer.expires = jiffies + predict_next_period_ready(min_buf_pos);
697719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettfor_each_linked_stream(s) {
698e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	s->pcm_buf_dma_ofs = min_buf_pos;
699ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (new_data > period_bytes) {
700719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (mmap) {
701ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			irq_pos = (irq_pos + period_bytes) % buffer_bytes;
702719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (playback) {
703ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				write(period_bytes);
704719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} else {
705ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				read(period_bytes);
706719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			}
707719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
708719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_period_elapsed(s);
709719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
710719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
711719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
712719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
713719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/** Minimum of 2 modulo values.  Works correctly when the difference between
714719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett* the values is less than half the modulus
715719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
716719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic inline unsigned int modulo_min(unsigned int a, unsigned int b,
717719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					unsigned long int modulus)
718719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
719719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int result;
720719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (((a-b) % modulus) < (modulus/2))
721719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		result = b;
722719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
723719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		result = a;
724719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
725719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return result;
726719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
727719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
728719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/** Timer function, equivalent to interrupt service routine for cards
729719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
730719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_timer_function(unsigned long data)
731719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
732719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data;
733ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	struct snd_pcm_substream *substream = dpcm->substream;
734ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
735719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime;
736719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_substream *s;
737719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int newdata = 0;
738e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	unsigned int pcm_buf_dma_ofs, min_buf_pos = 0;
739719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int remdata, xfercount, next_jiffies;
740719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int first = 1;
741ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	int loops = 0;
742719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 state;
743e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
744a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	DEBUG_NAME(substream, name);
745719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
746a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printdd("%s snd_card_asihpi_timer_function\n", name);
747ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
748719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* find minimum newdata and buffer pos in group */
749ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	snd_pcm_group_for_each_entry(s, substream) {
750719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
751719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		runtime = s->runtime;
752719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
753719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (snd_pcm_substream_chip(s) != card)
754719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			continue;
755719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
756ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		/* don't link Cap and Play */
757ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (substream->stream != s->stream)
758ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			continue;
759ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
760ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_stream_get_info_ex(
761719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					ds->h_stream, &state,
762e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett					&buffer_size, &bytes_avail,
763e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett					&samples_played, &on_card_bytes));
764719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
765719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* number of bytes in on-card buffer */
766e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		runtime->delay = on_card_bytes;
767719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
768f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett		if (!card->can_dma)
769f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			on_card_bytes = bytes_avail;
770f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett
771ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
772e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
773ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (state == HPI_STATE_STOPPED) {
774ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				if ((bytes_avail == 0) &&
775ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				    (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
776ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_handle_error(hpi_stream_start(ds->h_stream));
777b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett					snd_printdd("P%d start\n", s->number);
7780b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett					ds->drained_count = 0;
779ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				}
780ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			} else if (state == HPI_STATE_DRAINED) {
781b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett				snd_printd(KERN_WARNING "P%d drained\n",
782ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett						s->number);
7830b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett				ds->drained_count++;
7840b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett				if (ds->drained_count > 2) {
7850b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett					snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
7860b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett					continue;
7870b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett				}
7880b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett			} else {
7890b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1Eliot Blennerhassett				ds->drained_count = 0;
790ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			}
791ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		} else
792e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
793719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
794719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (first) {
795719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			/* can't statically init min when wrap is involved */
796e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			min_buf_pos = pcm_buf_dma_ofs;
797ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			newdata = (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes;
798719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			first = 0;
799719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		} else {
800719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			min_buf_pos =
801e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				modulo_min(min_buf_pos, pcm_buf_dma_ofs, UINT_MAX+1L);
802719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			newdata = min(
803ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				(pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes,
804719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				newdata);
805719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
806719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
807a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett		snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n",
808719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(unsigned long)frames_to_bytes(runtime,
809719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						runtime->status->hw_ptr),
810719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(unsigned long)frames_to_bytes(runtime,
811719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						runtime->control->appl_ptr));
812e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
813a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett		snd_printdd("%d S=%d, "
814a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett			"rw=0x%04X, dma=0x%04X, left=0x%04X, "
815a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett			"aux=0x%04X space=0x%04X\n",
816a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett			s->number, state,
817a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett			ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs,
818a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett			(int)bytes_avail,
819e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			(int)on_card_bytes, buffer_size-bytes_avail);
820ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		loops++;
821719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
822e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	pcm_buf_dma_ofs = min_buf_pos;
823719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
824ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	remdata = newdata % dpcm->period_bytes;
825ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	xfercount = newdata - remdata; /* a multiple of period_bytes */
826e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	/* come back when on_card_bytes has decreased enough to allow
827e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	   write to happen, or when data has been consumed to make another
828e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	   period
829e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	*/
830ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (xfercount && (on_card_bytes  > dpcm->period_bytes))
831ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		next_jiffies = ((on_card_bytes - dpcm->period_bytes) * HZ / dpcm->bytes_per_sec);
832e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	else
833ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		next_jiffies = ((dpcm->period_bytes - remdata) * HZ / dpcm->bytes_per_sec);
834e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
835e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	next_jiffies = max(next_jiffies, 1U);
836719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.expires = jiffies + next_jiffies;
837a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n",
838e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
839e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
840ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	snd_pcm_group_for_each_entry(s, substream) {
841719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
842719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
843ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		/* don't link Cap and Play */
844ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (substream->stream != s->stream)
845ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			continue;
846ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
847e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
848e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
849f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett		if (xfercount &&
850f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			/* Limit use of on card fifo for playback */
851f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			((on_card_bytes <= ds->period_bytes) ||
852f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			(s->stream == SNDRV_PCM_STREAM_CAPTURE)))
853f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett
854f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett		{
855f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett
856f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes;
857f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			unsigned int xfer1, xfer2;
858f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			char *pd = &s->runtime->dma_area[buf_ofs];
859f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett
860b0096a65677fa8d7e50975dc7282ce313610d9e8Eliot Blennerhassett			if (card->can_dma) { /* buffer wrap is handled at lower level */
861f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				xfer1 = xfercount;
862f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				xfer2 = 0;
863f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			} else {
864f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs);
865f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				xfer2 = xfercount - xfer1;
866f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			}
867f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett
868f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
869f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				snd_printddd("P%d write1 0x%04X 0x%04X\n",
870f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					s->number, xfer1, buf_ofs);
871f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				hpi_handle_error(
872f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					hpi_outstream_write_buf(
873f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett						ds->h_stream, pd, xfer1,
874f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett						&ds->format));
875f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett
876f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				if (xfer2) {
877f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					pd = s->runtime->dma_area;
878f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett
879f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					snd_printddd("P%d write2 0x%04X 0x%04X\n",
880719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							s->number,
881f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett							xfercount - xfer1, buf_ofs);
882719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_handle_error(
883719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						hpi_outstream_write_buf(
884f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett							ds->h_stream, pd,
885f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett							xfercount - xfer1,
886719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							&ds->format));
887f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				}
888f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			} else {
889f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				snd_printddd("C%d read1 0x%04x\n",
890f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					s->number, xfer1);
891f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				hpi_handle_error(
892f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					hpi_instream_read_buf(
893f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett						ds->h_stream,
894f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett						pd, xfer1));
895f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett				if (xfer2) {
896f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					pd = s->runtime->dma_area;
897f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					snd_printddd("C%d read2 0x%04x\n",
898f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett						s->number, xfer2);
899719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_handle_error(
900719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						hpi_instream_read_buf(
901ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett							ds->h_stream,
902f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett							pd, xfer2));
903719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				}
904f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			}
905f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
906e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
907719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			snd_pcm_period_elapsed(s);
908719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
909719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
910719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
911719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (dpcm->respawn_timer)
912719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		add_timer(&dpcm->timer);
913719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
914719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
915719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/***************************** PLAYBACK OPS ****************/
916719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
917719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					  unsigned int cmd, void *arg)
918719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
919a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd);
920719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_pcm_lib_ioctl(substream, cmd, arg);
921719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
922719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
923719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
924719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    substream)
925719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
926719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
927719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
928719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
929a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printdd("P%d prepare\n", substream->number);
930719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
931ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
932e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_host_rw_ofs = 0;
933e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_dma_ofs = 0;
934e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_elapsed_dma_ofs = 0;
935719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
936719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
937719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
938719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic snd_pcm_uframes_t
939719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettsnd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
940719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
941719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
942719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
943719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_uframes_t ptr;
944719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
945ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs  % dpcm->buffer_bytes);
946a6477134db119a22aa30911ff18e440b8db9df65Eliot Blennerhassett	snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr);
947719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ptr;
948719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
949719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
950719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
951719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						u32 h_stream,
952719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						struct snd_pcm_hardware *pcmhw)
953719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
954719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_format hpi_format;
955719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 format;
956719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
957719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
958719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 sample_rate = 48000;
959719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
960719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* on cards without SRC, must query at valid rate,
961719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	* maybe set by external sync
962719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
963ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_mixer_get_control(asihpi->h_mixer,
964719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
965719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_CONTROL_SAMPLECLOCK, &h_control);
966719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
967719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err)
968ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_sample_clock_get_sample_rate(h_control,
969719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&sample_rate);
970719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
971719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (format = HPI_FORMAT_PCM8_UNSIGNED;
972719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	     format <= HPI_FORMAT_PCM24_SIGNED; format++) {
973719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = hpi_format_create(&hpi_format,
974719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					2, format, sample_rate, 128000, 0);
975719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err)
976ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			err = hpi_outstream_query_format(h_stream,
977719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							&hpi_format);
978719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err && (hpi_to_alsa_formats[format] != -1))
979719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			pcmhw->formats |=
980719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				(1ULL << hpi_to_alsa_formats[format]);
981719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
982719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
983719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
984719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_hardware snd_card_asihpi_playback = {
985719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.channels_min = 1,
986719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.channels_max = 2,
987719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.buffer_bytes_max = BUFFER_BYTES_MAX,
988719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.period_bytes_min = PERIOD_BYTES_MIN,
989719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
990719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.periods_min = PERIODS_MIN,
991719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
992719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.fifo_size = 0,
993719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
994719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
995719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
996719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
997719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
998719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm;
999719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
1000719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
1001719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1002719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
1003719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (dpcm == NULL)
1004719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENOMEM;
1005719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1006719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err =
1007ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_outstream_open(card->adapter_index,
1008719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      substream->number, &dpcm->h_stream);
1009719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_error(err);
1010719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
1011719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		kfree(dpcm);
1012719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
1013719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EBUSY;
1014719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
1015719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EIO;
1016719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1017719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*? also check ASI5000 samplerate source
1018719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    If external, only support external rate.
101925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	    If internal and other stream playing, can't switch
1020719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1021719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1022719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	init_timer(&dpcm->timer);
1023719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.data = (unsigned long) dpcm;
1024719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.function = snd_card_asihpi_timer_function;
1025719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->substream = substream;
1026719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->private_data = dpcm;
1027719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->private_free = snd_card_asihpi_runtime_free;
1028719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1029719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_playback.channels_max = card->out_max_chans;
1030719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*?snd_card_asihpi_playback.period_bytes_min =
1031719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	card->out_max_chans * 4096; */
1032719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1033719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_playback_format(card, dpcm->h_stream,
1034719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					&snd_card_asihpi_playback);
1035719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1036719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_playback);
1037719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1038719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED |
1039719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_INFO_DOUBLE |
1040719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_INFO_BATCH |
1041719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_INFO_BLOCK_TRANSFER |
1042f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					SNDRV_PCM_INFO_PAUSE |
1043f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					SNDRV_PCM_INFO_MMAP |
1044f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					SNDRV_PCM_INFO_MMAP_VALID;
1045719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1046719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (card->support_grouping)
1047719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
1048719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1049719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* struct is copied, so can create initializer dynamically */
1050719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->hw = snd_card_asihpi_playback;
1051719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1052f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	if (card->can_dma)
1053719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = snd_pcm_hw_constraint_pow2(runtime, 0,
1054719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1055719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
1056719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
1057719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1058719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1059719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		card->update_interval_frames);
106026aebef420f8036213419b8a46e3a07db51439cdEliot Blennerhassett
1061719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1062e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		card->update_interval_frames * 2, UINT_MAX);
1063719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1064719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_set_sync(substream);
1065719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1066b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett	snd_printdd("playback open\n");
1067719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1068719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1069719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1070719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1071719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
1072719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1073719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1074719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1075719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1076ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_outstream_close(dpcm->h_stream));
1077b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett	snd_printdd("playback close\n");
1078719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1079719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1080719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1081719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1082719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
1083719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.open = snd_card_asihpi_playback_open,
1084719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.close = snd_card_asihpi_playback_close,
1085719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.ioctl = snd_card_asihpi_playback_ioctl,
1086719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_params = snd_card_asihpi_pcm_hw_params,
1087719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_free = snd_card_asihpi_hw_free,
1088719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.prepare = snd_card_asihpi_playback_prepare,
1089719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.trigger = snd_card_asihpi_trigger,
1090719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.pointer = snd_card_asihpi_playback_pointer,
1091719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1092719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1093719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/***************************** CAPTURE OPS ****************/
1094719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic snd_pcm_uframes_t
1095719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettsnd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
1096719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1097719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1098719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1099719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1100b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett	snd_printddd("capture pointer %d=%d\n",
1101e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			substream->number, dpcm->pcm_buf_dma_ofs);
1102e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	/* NOTE Unlike playback can't use actual samples_played
1103719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		for the capture position, because those samples aren't yet in
1104719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		the local buffer available for reading.
1105719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1106ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	return bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
1107719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1108719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1109719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_ioctl(struct snd_pcm_substream *substream,
1110719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					 unsigned int cmd, void *arg)
1111719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1112719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_pcm_lib_ioctl(substream, cmd, arg);
1113719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1114719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1115719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
1116719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1117719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1118719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1119719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1120ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_reset(dpcm->h_stream));
1121e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_host_rw_ofs = 0;
1122e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_dma_ofs = 0;
1123e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_elapsed_dma_ofs = 0;
1124719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1125b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett	snd_printdd("Capture Prepare %d\n", substream->number);
1126719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1127719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1128719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1129719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1130719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1131719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
1132719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					u32 h_stream,
1133719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					 struct snd_pcm_hardware *pcmhw)
1134719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1135719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett  struct hpi_format hpi_format;
1136719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 format;
1137719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1138719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
1139719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 sample_rate = 48000;
1140719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1141719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* on cards without SRC, must query at valid rate,
1142719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		maybe set by external sync */
1143ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_mixer_get_control(asihpi->h_mixer,
1144719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
1145719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_CONTROL_SAMPLECLOCK, &h_control);
1146719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1147719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err)
1148ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_sample_clock_get_sample_rate(h_control,
1149719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			&sample_rate);
1150719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1151719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (format = HPI_FORMAT_PCM8_UNSIGNED;
1152719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		format <= HPI_FORMAT_PCM24_SIGNED; format++) {
1153719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1154719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = hpi_format_create(&hpi_format, 2, format,
1155719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				sample_rate, 128000, 0);
1156719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err)
1157ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			err = hpi_instream_query_format(h_stream,
1158719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    &hpi_format);
1159719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err)
1160719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			pcmhw->formats |=
1161719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				(1ULL << hpi_to_alsa_formats[format]);
1162719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1163719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1164719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1165719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1166719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_hardware snd_card_asihpi_capture = {
1167719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.channels_min = 1,
1168719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.channels_max = 2,
1169719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.buffer_bytes_max = BUFFER_BYTES_MAX,
1170719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.period_bytes_min = PERIOD_BYTES_MIN,
1171719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
1172719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.periods_min = PERIODS_MIN,
1173719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
1174719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.fifo_size = 0,
1175719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1176719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1177719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
1178719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1179719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1180719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
1181719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm;
1182719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
1183719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1184719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
1185719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (dpcm == NULL)
1186719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENOMEM;
1187719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1188b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett	snd_printdd("capture open adapter %d stream %d\n",
1189719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   card->adapter_index, substream->number);
1190719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1191719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = hpi_handle_error(
1192ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_instream_open(card->adapter_index,
1193719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			     substream->number, &dpcm->h_stream));
1194719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
1195719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		kfree(dpcm);
1196719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
1197719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EBUSY;
1198719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
1199719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EIO;
1200719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1201719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1202719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	init_timer(&dpcm->timer);
1203719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.data = (unsigned long) dpcm;
1204719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.function = snd_card_asihpi_timer_function;
1205719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->substream = substream;
1206719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->private_data = dpcm;
1207719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->private_free = snd_card_asihpi_runtime_free;
1208719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1209719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_capture.channels_max = card->in_max_chans;
1210719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_capture_format(card, dpcm->h_stream,
1211719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				       &snd_card_asihpi_capture);
1212719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_capture);
1213f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |
1214f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					SNDRV_PCM_INFO_MMAP |
1215f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett					SNDRV_PCM_INFO_MMAP_VALID;
1216719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1217e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	if (card->support_grouping)
1218e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
1219e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
1220719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->hw = snd_card_asihpi_capture;
1221719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1222f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	if (card->can_dma)
1223719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = snd_pcm_hw_constraint_pow2(runtime, 0,
1224719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1225719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
1226719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
1227719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1228719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1229719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		card->update_interval_frames);
1230719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1231719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		card->update_interval_frames * 2, UINT_MAX);
1232719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1233719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_set_sync(substream);
1234719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1235719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1236719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1237719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1238719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
1239719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1240719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
1241719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1242ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_close(dpcm->h_stream));
1243719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1244719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1245719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1246719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
1247719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.open = snd_card_asihpi_capture_open,
1248719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.close = snd_card_asihpi_capture_close,
1249719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.ioctl = snd_card_asihpi_capture_ioctl,
1250719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_params = snd_card_asihpi_pcm_hw_params,
1251719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_free = snd_card_asihpi_hw_free,
1252719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.prepare = snd_card_asihpi_capture_prepare,
1253719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.trigger = snd_card_asihpi_trigger,
1254719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.pointer = snd_card_asihpi_capture_pointer,
1255719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1256719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1257719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
1258719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				      int device, int substreams)
1259719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1260719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm *pcm;
1261719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
1262719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1263e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,
1264719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			 asihpi->num_outstreams, asihpi->num_instreams,
1265719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			 &pcm);
1266719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
1267719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
1268719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* pointer to ops struct is stored, dont change ops afterwards! */
1269719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1270719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&snd_card_asihpi_playback_mmap_ops);
1271719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1272719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&snd_card_asihpi_capture_mmap_ops);
1273719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1274719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcm->private_data = asihpi;
1275719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcm->info_flags = 0;
1276e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	strcpy(pcm->name, "Asihpi PCM");
1277719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1278719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*? do we want to emulate MMAP for non-BBM cards?
1279719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
1280719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1281719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						snd_dma_pci_data(asihpi->pci),
1282719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						64*1024, BUFFER_BYTES_MAX);
1283719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1284719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1285719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1286719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1287719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/***************************** MIXER CONTROLS ****************/
1288719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct hpi_control {
1289719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
1290719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 control_type;
1291719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 src_node_type;
1292719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 src_node_index;
1293719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 dst_node_type;
1294719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 dst_node_index;
1295719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 band;
1296719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
1297719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1298719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1299ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic const char * const asihpi_tuner_band_names[] = {
1300719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"invalid",
1301719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"AM",
1302719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"FM mono",
1303719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV NTSC-M",
1304719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"FM stereo",
1305719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"AUX",
1306719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV PAL BG",
1307719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV PAL I",
1308719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV PAL DK",
1309719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV SECAM",
1310719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1311719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1312719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettcompile_time_assert(
1313719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	(ARRAY_SIZE(asihpi_tuner_band_names) ==
1314719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		(HPI_TUNER_BAND_LAST+1)),
1315719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	assert_tuner_band_names_size);
1316719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1317ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic const char * const asihpi_src_names[] = {
1318719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"no source",
1319e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"PCM",
1320e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Line",
1321e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Digital",
1322e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Tuner",
1323719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"RF",
1324e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Clock",
1325e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Bitstream",
1326e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Microphone",
1327e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Cobranet",
1328e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Analog",
1329e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Adapter",
1330719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1331719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1332719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettcompile_time_assert(
1333719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	(ARRAY_SIZE(asihpi_src_names) ==
1334168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		(HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
1335719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	assert_src_names_size);
1336719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1337ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic const char * const asihpi_dst_names[] = {
1338719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"no destination",
1339e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"PCM",
1340e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Line",
1341e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Digital",
1342719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"RF",
1343e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Speaker",
1344e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Cobranet Out",
1345e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Analog"
1346719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1347719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1348719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettcompile_time_assert(
1349719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	(ARRAY_SIZE(asihpi_dst_names) ==
1350168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		(HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
1351719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	assert_dst_names_size);
1352719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1353719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
1354719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_card_asihpi *asihpi)
1355719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1356719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
1357719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1358719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi));
1359719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
1360719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
1361719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else if (mixer_dump)
1362719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index);
1363719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1364719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1365719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1366719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1367719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Convert HPI control name and location into ALSA control name */
1368719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
1369719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct hpi_control *hpi_ctl,
1370719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				char *name)
1371719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1372550ac6ba4ef0e57f6edbadf2b018d5125d2f7e98Eliot Blennerhassett	char *dir;
1373719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	memset(snd_control, 0, sizeof(*snd_control));
1374719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control->name = hpi_ctl->name;
1375719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control->private_value = hpi_ctl->h_control;
1376719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1377719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control->index = 0;
1378719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1379550ac6ba4ef0e57f6edbadf2b018d5125d2f7e98Eliot Blennerhassett	if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE)
1380550ac6ba4ef0e57f6edbadf2b018d5125d2f7e98Eliot Blennerhassett		dir = ""; /* clock is neither capture nor playback */
1381550ac6ba4ef0e57f6edbadf2b018d5125d2f7e98Eliot Blennerhassett	else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
1382e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir = "Capture ";  /* On or towards a PCM capture destination*/
1383e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1384e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		(!hpi_ctl->dst_node_type))
1385e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir = "Capture "; /* On a source node that is not PCM playback */
1386ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	else if (hpi_ctl->src_node_type &&
1387ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		(hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1388e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		(hpi_ctl->dst_node_type))
1389e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir = "Monitor Playback "; /* Between an input and an output */
1390e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	else
1391e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir = "Playback "; /* PCM Playback source, or  output node */
1392e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
1393719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
1394550ac6ba4ef0e57f6edbadf2b018d5125d2f7e98Eliot Blennerhassett		sprintf(hpi_ctl->name, "%s %d %s %d %s%s",
1395719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi_src_names[hpi_ctl->src_node_type],
1396719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			hpi_ctl->src_node_index,
1397719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi_dst_names[hpi_ctl->dst_node_type],
1398719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			hpi_ctl->dst_node_index,
1399e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			dir, name);
1400719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else if (hpi_ctl->dst_node_type) {
1401e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		sprintf(hpi_ctl->name, "%s %d %s%s",
1402719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi_dst_names[hpi_ctl->dst_node_type],
1403719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_ctl->dst_node_index,
1404e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir, name);
1405719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	} else {
1406e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		sprintf(hpi_ctl->name, "%s %d %s%s",
1407719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi_src_names[hpi_ctl->src_node_type],
1408719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_ctl->src_node_index,
1409e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir, name);
1410719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1411ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	/* printk(KERN_INFO "Adding %s %d to %d ",  hpi_ctl->name,
1412ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */
1413719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1414719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1415719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
1416719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Volume controls
1417719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
1418719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define VOL_STEP_mB 1
1419719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
1420719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1421719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1422719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1423719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1424719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* native gains are in millibels */
1425719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short min_gain_mB;
1426719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short max_gain_mB;
1427719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short step_gain_mB;
1428719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1429ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_volume_query_range(h_control,
1430719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			&min_gain_mB, &max_gain_mB, &step_gain_mB);
1431719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err) {
1432719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		max_gain_mB = 0;
1433719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		min_gain_mB = -10000;
1434719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		step_gain_mB = VOL_STEP_mB;
1435719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1436719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1437719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1438719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 2;
1439719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;
1440719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;
1441719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;
1442719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1443719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1444719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1445719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
1446719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1447719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1448719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1449719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS];
1450719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1451ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_volume_get_gain(h_control, an_gain_mB));
1452719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;
1453719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;
1454719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1455719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1456719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1457719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1458719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
1459719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1460719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1461719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
1462719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1463719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS];
1464719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1465719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	an_gain_mB[0] =
1466719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    (ucontrol->value.integer.value[0]) * VOL_STEP_mB;
1467719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	an_gain_mB[1] =
1468719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    (ucontrol->value.integer.value[1]) * VOL_STEP_mB;
1469719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*  change = asihpi->mixer_volume[addr][0] != left ||
1470719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   asihpi->mixer_volume[addr][1] != right;
1471719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 */
1472719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
1473ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
1474719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
1475719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1476719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1477719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
1478719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1479719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
1480719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1481719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1482719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1483719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1484719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1485e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
1486719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1487719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1488719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_volume_info;
1489719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_volume_get;
1490719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_volume_put;
1491719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.tlv.p = db_scale_100;
1492719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1493719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1494719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1495719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1496719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
1497719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Level controls
1498719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
1499719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,
1500719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_info *uinfo)
1501719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1502719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1503719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1504719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short min_gain_mB;
1505719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short max_gain_mB;
1506719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short step_gain_mB;
1507719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1508719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err =
1509ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_level_query_range(h_control, &min_gain_mB,
1510719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			       &max_gain_mB, &step_gain_mB);
1511719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err) {
1512719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		max_gain_mB = 2400;
1513719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		min_gain_mB = -1000;
1514719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		step_gain_mB = 100;
1515719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1516719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1517719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1518719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 2;
1519719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB;
1520719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB;
1521719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB;
1522719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1523719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1524719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1525719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,
1526719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
1527719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1528719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1529719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS];
1530719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1531ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_level_get_gain(h_control, an_gain_mB));
1532719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] =
1533719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    an_gain_mB[0] / HPI_UNITS_PER_dB;
1534719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[1] =
1535719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    an_gain_mB[1] / HPI_UNITS_PER_dB;
1536719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1537719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1538719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1539719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1540719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,
1541719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
1542719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1543719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
1544719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1545719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS];
1546719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1547719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	an_gain_mB[0] =
1548719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1549719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	an_gain_mB[1] =
1550719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB;
1551719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*  change = asihpi->mixer_level[addr][0] != left ||
1552719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   asihpi->mixer_level[addr][1] != right;
1553719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 */
1554719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
1555ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_level_set_gain(h_control, an_gain_mB));
1556719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
1557719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1558719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1559719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0);
1560719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1561719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
1562719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1563719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1564719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1565719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1566719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1567719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* can't use 'volume' cos some nodes have volume as well */
1568e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Level");
1569719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1570719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1571719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_level_info;
1572719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_level_get;
1573719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_level_put;
1574719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.tlv.p = db_scale_level;
1575719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1576719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1577719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1578719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1579719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
1580719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   AESEBU controls
1581719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
1582719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1583719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* AESEBU format */
1584ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic const char * const asihpi_aesebu_format_names[] = {
1585ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"N/A", "S/PDIF", "AES/EBU" };
1586719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1587719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
1588719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1589719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1590719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1591719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1592719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.enumerated.items = 3;
1593719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1594719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1595719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		uinfo->value.enumerated.item =
1596719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			uinfo->value.enumerated.items - 1;
1597719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1598719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	strcpy(uinfo->value.enumerated.name,
1599719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
1600719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1601719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1602719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1603719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1604719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
1605719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			struct snd_ctl_elem_value *ucontrol,
1606ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			u16 (*func)(u32, u16 *))
1607719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1608719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1609719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source, err;
1610719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1611ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = func(h_control, &source);
1612719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1613719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* default to N/A */
1614719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = 0;
1615719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* return success but set the control to N/A */
1616719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
1617719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return 0;
1618719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (source == HPI_AESEBU_FORMAT_SPDIF)
1619719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.enumerated.item[0] = 1;
1620719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (source == HPI_AESEBU_FORMAT_AESEBU)
1621719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.enumerated.item[0] = 2;
1622719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1623719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1624719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1625719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1626719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
1627719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			struct snd_ctl_elem_value *ucontrol,
1628ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			 u16 (*func)(u32, u16))
1629719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1630719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1631719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1632719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* default to S/PDIF */
1633719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source = HPI_AESEBU_FORMAT_SPDIF;
1634719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1635719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ucontrol->value.enumerated.item[0] == 1)
1636719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		source = HPI_AESEBU_FORMAT_SPDIF;
1637719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ucontrol->value.enumerated.item[0] == 2)
1638719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		source = HPI_AESEBU_FORMAT_AESEBU;
1639719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1640ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (func(h_control, source) != 0)
1641719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
1642719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1643719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 1;
1644719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1645719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1646719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,
1647719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1648719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
1649ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_aesebu_receiver_get_format);
1650719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1651719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1652719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,
1653719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1654719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
1655ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_aesebu_receiver_set_format);
1656719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1657719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1658719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol,
1659719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1660719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1661719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1662719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1663719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1664719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = 0;
1665719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = 0X1F;
1666719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = 1;
1667719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1668719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1669719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1670719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1671719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,
1672719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1673719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1674719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1675719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 status;
1676719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1677ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_aesebu_receiver_get_error_status(
1678ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					 h_control, &status));
1679719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] = status;
1680719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1681719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1682719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1683719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
1684719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1685719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1686719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1687719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1688719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1689e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
1690719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1691719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_aesebu_format_info;
1692719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_aesebu_rx_format_get;
1693719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_aesebu_rx_format_put;
1694719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1695719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1696719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ctl_add(card, &snd_control, asihpi) < 0)
1697719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
1698719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1699e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Status");
1700719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access =
1701719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
1702719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_aesebu_rxstatus_info;
1703719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_aesebu_rxstatus_get;
1704719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1705719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1706719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1707719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1708719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,
1709719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1710719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
1711ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_aesebu_transmitter_get_format);
1712719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1713719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1714719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,
1715719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1716719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
1717ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_aesebu_transmitter_set_format);
1718719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1719719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1720719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1721719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,
1722719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1723719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1724719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1725719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1726719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1727e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
1728719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1729719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_aesebu_format_info;
1730719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_aesebu_tx_format_get;
1731719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_aesebu_tx_format_put;
1732719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1733719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1734719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1735719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1736719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
1737719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Tuner controls
1738719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
1739719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1740719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Gain */
1741719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1742719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,
1743719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1744719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1745719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1746719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1747719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short idx;
1748719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 gain_range[3];
1749719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1750719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (idx = 0; idx < 3; idx++) {
1751ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_tuner_query_gain(h_control,
1752719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					  idx, &gain_range[idx]);
1753719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err != 0)
1754719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return err;
1755719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1756719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1757719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1758719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1759719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB;
1760719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB;
1761719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB;
1762719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1763719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1764719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1765719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,
1766719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1767719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1768719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*
1769719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1770719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1771719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1772719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short gain;
1773719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1774ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_get_gain(h_control, &gain));
1775719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
1776719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1777719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1778719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1779719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1780719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,
1781719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1782719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1783719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*
1784719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1785719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1786719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1787719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short gain;
1788719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1789719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1790ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_set_gain(h_control, gain));
1791719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1792719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 1;
1793719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1794719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1795719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Band  */
1796719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1797719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,
1798719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					u16 *band_list, u32 len) {
1799719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1800719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err = 0;
1801719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 i;
1802719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1803719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i < len; i++) {
1804ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_tuner_query_band(
1805719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				h_control, i, &band_list[i]);
1806719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err != 0)
1807719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
1808719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1809719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1810719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX))
1811719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EIO;
1812719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1813719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return i;
1814719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1815719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1816719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
1817719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1818719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1819719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 tuner_bands[HPI_TUNER_BAND_LAST];
1820719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int num_bands = 0;
1821719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1822719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1823719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_TUNER_BAND_LAST);
1824719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1825719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (num_bands < 0)
1826719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return num_bands;
1827719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1828719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1829719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1830719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.enumerated.items = num_bands;
1831719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1832719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (num_bands > 0) {
1833719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (uinfo->value.enumerated.item >=
1834719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					uinfo->value.enumerated.items)
1835719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			uinfo->value.enumerated.item =
1836719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				uinfo->value.enumerated.items - 1;
1837719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1838719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		strcpy(uinfo->value.enumerated.name,
1839719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi_tuner_band_names[
1840719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				tuner_bands[uinfo->value.enumerated.item]]);
1841719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1842719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1843719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1844719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1845719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1846719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
1847719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1848719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1849719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1850719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*
1851719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1852719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1853719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 band, idx;
1854719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 tuner_bands[HPI_TUNER_BAND_LAST];
1855719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 num_bands = 0;
1856719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1857719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1858719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_TUNER_BAND_LAST);
1859719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1860ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_get_band(h_control, &band));
1861719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1862719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = -1;
1863719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
1864719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (tuner_bands[idx] == band) {
1865719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.enumerated.item[0] = idx;
1866719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
1867719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
1868719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1869719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1870719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1871719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1872719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
1873719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1874719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1875719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*
1876719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1877719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1878719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1879719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 band;
1880719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 tuner_bands[HPI_TUNER_BAND_LAST];
1881719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 num_bands = 0;
1882719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1883719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1884719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			HPI_TUNER_BAND_LAST);
1885719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1886719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	band = tuner_bands[ucontrol->value.enumerated.item[0]];
1887ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_set_band(h_control, band));
1888719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1889719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 1;
1890719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1891719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1892719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Freq */
1893719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1894719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,
1895719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1896719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1897719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1898719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1899719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 tuner_bands[HPI_TUNER_BAND_LAST];
1900719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 num_bands = 0, band_iter, idx;
1901719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 freq_range[3], temp_freq_range[3];
1902719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1903719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1904719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			HPI_TUNER_BAND_LAST);
1905719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1906719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	freq_range[0] = INT_MAX;
1907719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	freq_range[1] = 0;
1908719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	freq_range[2] = INT_MAX;
1909719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1910719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (band_iter = 0; band_iter < num_bands; band_iter++) {
1911719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		for (idx = 0; idx < 3; idx++) {
1912ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			err = hpi_tuner_query_frequency(h_control,
1913719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				idx, tuner_bands[band_iter],
1914719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&temp_freq_range[idx]);
1915719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (err != 0)
1916719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				return err;
1917719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
1918719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1919719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* skip band with bogus stepping */
1920719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (temp_freq_range[2] <= 0)
1921719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			continue;
1922719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1923719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (temp_freq_range[0] < freq_range[0])
1924719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			freq_range[0] = temp_freq_range[0];
1925719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (temp_freq_range[1] > freq_range[1])
1926719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			freq_range[1] = temp_freq_range[1];
1927719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (temp_freq_range[2] < freq_range[2])
1928719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			freq_range[2] = temp_freq_range[2];
1929719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1930719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1931719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1932719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1933719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = ((int)freq_range[0]);
1934719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = ((int)freq_range[1]);
1935719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = ((int)freq_range[2]);
1936719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1937719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1938719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1939719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,
1940719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1941719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1942719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1943719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 freq;
1944719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1945ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_get_frequency(h_control, &freq));
1946719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] = freq;
1947719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1948719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1949719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1950719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1951719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,
1952719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1953719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1954719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1955719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 freq;
1956719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1957719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	freq = ucontrol->value.integer.value[0];
1958ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_set_frequency(h_control, freq));
1959719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1960719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 1;
1961719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1962719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1963719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Tuner control group initializer  */
1964719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
1965719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1966719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1967719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1968719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1969719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1970719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.private_value = hpi_ctl->h_control;
1971719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1972719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1973ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (!hpi_tuner_get_gain(hpi_ctl->h_control, NULL)) {
1974e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		asihpi_ctl_init(&snd_control, hpi_ctl, "Gain");
1975719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.info = snd_asihpi_tuner_gain_info;
1976719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.get = snd_asihpi_tuner_gain_get;
1977719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.put = snd_asihpi_tuner_gain_put;
1978719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1979719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (ctl_add(card, &snd_control, asihpi) < 0)
1980719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -EINVAL;
1981719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1982719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1983e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Band");
1984719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_tuner_band_info;
1985719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_tuner_band_get;
1986719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_tuner_band_put;
1987719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1988719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ctl_add(card, &snd_control, asihpi) < 0)
1989719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
1990719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1991e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Freq");
1992719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_tuner_freq_info;
1993719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_tuner_freq_get;
1994719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_tuner_freq_put;
1995719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1996719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1997719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1998719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1999719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2000719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Meter controls
2001719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2002719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,
2003719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_info *uinfo)
2004719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2005719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2006719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = HPI_MAX_CHANNELS;
2007719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = 0;
2008719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = 0x7FFFFFFF;
2009719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2010719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2011719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2012719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* linear values for 10dB steps */
2013719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int log2lin[] = {
2014719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	0x7FFFFFFF, /* 0dB */
2015719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	679093956,
2016719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	214748365,
2017719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 67909396,
2018719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 21474837,
2019719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	  6790940,
2020719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	  2147484, /* -60dB */
2021719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   679094,
2022719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   214748, /* -80 */
2023719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    67909,
2024719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    21475, /* -100 */
2025719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	     6791,
2026719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	     2147,
2027719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	      679,
2028719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	      214,
2029719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	       68,
2030719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	       21,
2031719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		7,
2032719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		2
2033719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
2034719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2035719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,
2036719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
2037719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2038719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2039719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS], i;
2040719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
2041719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2042ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_meter_get_peak(h_control, an_gain_mB);
2043719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2044719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i < HPI_MAX_CHANNELS; i++) {
2045719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err) {
2046719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.integer.value[i] = 0;
2047719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		} else if (an_gain_mB[i] >= 0) {
2048719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.integer.value[i] =
2049719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				an_gain_mB[i] << 16;
2050719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		} else {
2051719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			/* -ve is log value in millibels < -60dB,
2052719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			* convert to (roughly!) linear,
2053719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			*/
2054719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.integer.value[i] =
2055719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					log2lin[an_gain_mB[i] / -1000];
2056719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
2057719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2058719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2059719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2060719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2061719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,
2062719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl, int subidx)
2063719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2064719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2065719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2066719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2067e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Meter");
2068719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access =
2069719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2070719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_meter_info;
2071719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_meter_get;
2072719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2073719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.index = subidx;
2074719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2075719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2076719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2077719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2078719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2079719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Multiplexer controls
2080719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2081719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)
2082719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2083719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = snd_control->private_value;
2084719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_control hpi_ctl;
2085719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int s, err;
2086719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (s = 0; s < 32; s++) {
2087ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_multiplexer_query_source(h_control, s,
2088719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						  &hpi_ctl.
2089719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						  src_node_type,
2090719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						  &hpi_ctl.
2091719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						  src_node_index);
2092719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err)
2093719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2094719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2095719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return s;
2096719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2097719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2098719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
2099719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			       struct snd_ctl_elem_info *uinfo)
2100719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2101719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2102719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 src_node_type, src_node_index;
2103719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2104719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2105719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2106719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2107719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.enumerated.items =
2108719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    snd_card_asihpi_mux_count_sources(kcontrol);
2109719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2110719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2111719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		uinfo->value.enumerated.item =
2112719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    uinfo->value.enumerated.items - 1;
2113719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2114719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err =
2115ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_multiplexer_query_source(h_control,
2116719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					uinfo->value.enumerated.item,
2117719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					&src_node_type, &src_node_index);
2118719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2119719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	sprintf(uinfo->value.enumerated.name, "%s %d",
2120168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],
2121719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		src_node_index);
2122719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2123719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2124719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2125719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
2126719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      struct snd_ctl_elem_value *ucontrol)
2127719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2128719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2129719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source_type, source_index;
2130719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 src_node_type, src_node_index;
2131719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int s;
2132719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2133ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_multiplexer_get_source(h_control,
2134719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&source_type, &source_index));
2135719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* Should cache this search result! */
2136719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (s = 0; s < 256; s++) {
2137ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (hpi_multiplexer_query_source(h_control, s,
2138719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    &src_node_type, &src_node_index))
2139719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2140719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2141719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if ((source_type == src_node_type)
2142719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    && (source_index == src_node_index)) {
2143719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.enumerated.item[0] = s;
2144719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return 0;
2145719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
2146719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2147719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd(KERN_WARNING
2148e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"Control %x failed to match mux source %hu %hu\n",
2149719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		h_control, source_type, source_index);
2150719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = 0;
2151719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2152719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2153719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2154719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,
2155719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      struct snd_ctl_elem_value *ucontrol)
2156719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2157719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
2158719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2159719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source_type, source_index;
2160719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 e;
2161719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2162719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
2163719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2164ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	e = hpi_multiplexer_query_source(h_control,
2165719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    ucontrol->value.enumerated.item[0],
2166719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    &source_type, &source_index);
2167719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!e)
2168719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_handle_error(
2169ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			hpi_multiplexer_set_source(h_control,
2170719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						source_type, source_index));
2171719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
2172719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2173719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2174719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2175719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int  __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
2176719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
2177719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2178719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2179719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2180719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2181e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Route");
2182719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2183719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_mux_info;
2184719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_mux_get;
2185719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_mux_put;
2186719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2187719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2188719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2189719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2190719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2191719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2192719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Channel mode controls
2193719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2194719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
2195719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_info *uinfo)
2196719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2197e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	static const char * const mode_names[HPI_CHANNEL_MODE_LAST + 1] = {
2198e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"invalid",
2199e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"Normal", "Swap",
2200e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"From Left", "From Right",
2201e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"To Left", "To Right"
2202719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	};
2203719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2204719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2205719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 mode;
2206719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int i;
2207e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	u16 mode_map[6];
2208e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	int valid_modes = 0;
2209719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2210719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* HPI channel mode values can be from 1 to 6
2211719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	Some adapters only support a contiguous subset
2212719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
2213719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
2214e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		if (!hpi_channel_mode_query_mode(
2215ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			h_control, i, &mode)) {
2216e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			mode_map[valid_modes] = mode;
2217e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			valid_modes++;
2218e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			}
2219719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2220719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2221719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2222e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	uinfo->value.enumerated.items = valid_modes;
2223719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2224e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	if (uinfo->value.enumerated.item >= valid_modes)
2225e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		uinfo->value.enumerated.item = valid_modes - 1;
2226719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2227719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	strcpy(uinfo->value.enumerated.name,
2228e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	       mode_names[mode_map[uinfo->value.enumerated.item]]);
2229719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2230719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2231719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2232719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2233719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
2234719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
2235719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2236719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2237719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 mode;
2238719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2239ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (hpi_channel_mode_get(h_control, &mode))
2240719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		mode = 1;
2241719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2242719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = mode - 1;
2243719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2244719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2245719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2246719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2247719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,
2248719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
2249719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2250719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
2251719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2252719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2253719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
2254719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2255ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_channel_mode_set(h_control,
2256719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			   ucontrol->value.enumerated.item[0] + 1));
2257719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
2258719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2259719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2260719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2261719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
2262719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
2263719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2264719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2265719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2266719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2267e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Mode");
2268719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2269719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_cmode_info;
2270719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_cmode_get;
2271719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_cmode_put;
2272719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2273719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2274719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2275719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2276719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2277719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Sampleclock source  controls
2278719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2279ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic char *sampleclock_sources[MAX_CLOCKSOURCES] = {
2280ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
2281ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"SMPTE", "Digital1", "Auto", "Network", "Invalid",
2282ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"Prev Module",
2283ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"Digital2", "Digital3", "Digital4", "Digital5",
2284ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"Digital6", "Digital7", "Digital8"};
2285719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2286719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
2287719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
2288719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2289719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi =
2290719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(struct snd_card_asihpi *)(kcontrol->private_data);
2291719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache *clkcache = &asihpi->cc;
2292719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2293719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2294719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.enumerated.items = clkcache->count;
2295719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2296719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2297719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		uinfo->value.enumerated.item =
2298719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				uinfo->value.enumerated.items - 1;
2299719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2300719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	strcpy(uinfo->value.enumerated.name,
2301719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	       clkcache->s[uinfo->value.enumerated.item].name);
2302719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2303719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2304719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2305719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
2306719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
2307719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2308719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi =
2309719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(struct snd_card_asihpi *)(kcontrol->private_data);
2310719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache *clkcache = &asihpi->cc;
2311719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2312719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source, srcindex = 0;
2313719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int i;
2314719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2315719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = 0;
2316ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (hpi_sample_clock_get_source(h_control, &source))
2317719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		source = 0;
2318719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2319719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2320ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (hpi_sample_clock_get_source_index(h_control, &srcindex))
2321719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			srcindex = 0;
2322719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2323719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i < clkcache->count; i++)
2324719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if ((clkcache->s[i].source == source) &&
2325719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(clkcache->s[i].index == srcindex))
2326719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2327719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2328719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = i;
2329719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2330719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2331719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2332719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2333719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
2334719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
2335719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2336719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi =
2337719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(struct snd_card_asihpi *)(kcontrol->private_data);
2338719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache *clkcache = &asihpi->cc;
2339719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change, item;
2340719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2341719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2342719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
2343719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	item = ucontrol->value.enumerated.item[0];
2344719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (item >= clkcache->count)
2345719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		item = clkcache->count-1;
2346719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2347ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_sample_clock_set_source(
2348719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				h_control, clkcache->s[item].source));
2349719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2350719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2351ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_sample_clock_set_source_index(
2352719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				h_control, clkcache->s[item].index));
2353719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
2354719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2355719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2356719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2357719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Clkrate controls
2358719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2359719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Need to change this to enumerated control with list of rates */
2360719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol,
2361719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				   struct snd_ctl_elem_info *uinfo)
2362719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2363719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2364719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2365719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = 8000;
2366719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = 192000;
2367719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = 100;
2368719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2369719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2370719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2371719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2372719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,
2373719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_value *ucontrol)
2374719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2375719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2376719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 rate;
2377719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 e;
2378719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2379ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	e = hpi_sample_clock_get_local_rate(h_control, &rate);
2380719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!e)
2381719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.integer.value[0] = rate;
2382719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2383719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.integer.value[0] = 0;
2384719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2385719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2386719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2387719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,
2388719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_value *ucontrol)
2389719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2390719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
2391719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2392719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2393719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*  change = asihpi->mixer_clkrate[addr][0] != left ||
2394719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   asihpi->mixer_clkrate[addr][1] != right;
2395719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 */
2396719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
2397ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_sample_clock_set_local_rate(h_control,
2398719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				      ucontrol->value.integer.value[0]));
2399719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
2400719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2401719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2402719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol,
2403719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				   struct snd_ctl_elem_info *uinfo)
2404719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2405719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2406719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2407719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = 8000;
2408719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = 192000;
2409719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = 100;
2410719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2411719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2412719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2413719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2414719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
2415719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_value *ucontrol)
2416719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2417719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2418719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 rate;
2419719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 e;
2420719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2421ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	e = hpi_sample_clock_get_sample_rate(h_control, &rate);
2422719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!e)
2423719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.integer.value[0] = rate;
2424719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2425719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.integer.value[0] = 0;
2426719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2427719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2428719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2429719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
2430719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
2431719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2432719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2433719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2434719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2435719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache *clkcache = &asihpi->cc;
2436719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 hSC =  hpi_ctl->h_control;
2437719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int has_aes_in = 0;
2438719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int i, j;
2439719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source;
2440719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2441719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.private_value = hpi_ctl->h_control;
2442719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2443719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	clkcache->has_local = 0;
2444719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2445719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {
2446ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if  (hpi_sample_clock_query_source(hSC,
2447719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				i, &source))
2448719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2449719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		clkcache->s[i].source = source;
2450719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		clkcache->s[i].index = 0;
2451719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		clkcache->s[i].name = sampleclock_sources[source];
2452719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2453719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			has_aes_in = 1;
2454719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL)
2455719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			clkcache->has_local = 1;
2456719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2457719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (has_aes_in)
2458719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* already will have picked up index 0 above */
2459719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		for (j = 1; j < 8; j++) {
2460ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (hpi_sample_clock_query_source_index(hSC,
2461719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,
2462719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&source))
2463719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
2464719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			clkcache->s[i].source =
2465719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT;
2466719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			clkcache->s[i].index = j;
2467719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			clkcache->s[i].name = sampleclock_sources[
2468719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					j+HPI_SAMPLECLOCK_SOURCE_LAST];
2469719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			i++;
2470719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
2471719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	clkcache->count = i;
2472719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2473e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Source");
2474719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2475719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_clksrc_info;
2476719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_clksrc_get;
2477719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_clksrc_put;
2478719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ctl_add(card, &snd_control, asihpi) < 0)
2479719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
2480719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2481719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2482719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (clkcache->has_local) {
2483e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		asihpi_ctl_init(&snd_control, hpi_ctl, "Localrate");
2484719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2485719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.info = snd_asihpi_clklocal_info;
2486719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.get = snd_asihpi_clklocal_get;
2487719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.put = snd_asihpi_clklocal_put;
2488719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2489719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2490719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (ctl_add(card, &snd_control, asihpi) < 0)
2491719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -EINVAL;
2492719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2493719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2494e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Rate");
2495719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access =
2496719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2497719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_clkrate_info;
2498719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_clkrate_get;
2499719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2500719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2501719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2502719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2503719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Mixer
2504719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2505719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2506719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
2507719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2508719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2509719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int idx = 0;
2510719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int subindex = 0;
2511719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2512719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_control hpi_ctl, prev_ctl;
2513719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2514719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (snd_BUG_ON(!asihpi))
2515719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
2516e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	strcpy(card->mixername, "Asihpi Mixer");
2517719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2518719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err =
2519ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_mixer_open(asihpi->adapter_index,
2520719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			  &asihpi->h_mixer);
2521719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_error(err);
2522719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
2523719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -err;
2524719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
252521896bc010c17e5ac58951e771496ec2fb1051edTakashi Iwai	memset(&prev_ctl, 0, sizeof(prev_ctl));
252621896bc010c17e5ac58951e771496ec2fb1051edTakashi Iwai	prev_ctl.control_type = -1;
252721896bc010c17e5ac58951e771496ec2fb1051edTakashi Iwai
2528719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (idx = 0; idx < 2000; idx++) {
2529719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = hpi_mixer_get_control_by_index(
2530ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				asihpi->h_mixer,
2531719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				idx,
2532719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.src_node_type,
2533719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.src_node_index,
2534719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.dst_node_type,
2535719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.dst_node_index,
2536719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.control_type,
2537719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.h_control);
2538719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err) {
2539719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (err == HPI_ERROR_CONTROL_DISABLED) {
2540719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				if (mixer_dump)
2541719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					snd_printk(KERN_INFO
2542e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett						   "Disabled HPI Control(%d)\n",
2543719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						   idx);
2544719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				continue;
2545719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} else
2546719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
2547719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2548719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
2549719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2550168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;
2551168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;
2552719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2553719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* ASI50xx in SSX mode has multiple meters on the same node.
2554719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   Use subindex to create distinct ALSA controls
2555719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   for any duplicated controls.
2556719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		*/
2557719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if ((hpi_ctl.control_type == prev_ctl.control_type) &&
2558719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    (hpi_ctl.src_node_type == prev_ctl.src_node_type) &&
2559719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    (hpi_ctl.src_node_index == prev_ctl.src_node_index) &&
2560719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) &&
2561719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    (hpi_ctl.dst_node_index == prev_ctl.dst_node_index))
2562719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			subindex++;
2563719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		else
2564719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			subindex = 0;
2565719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2566719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		prev_ctl = hpi_ctl;
2567719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2568719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		switch (hpi_ctl.control_type) {
2569719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_VOLUME:
2570719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_volume_add(asihpi, &hpi_ctl);
2571719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2572719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_LEVEL:
2573719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_level_add(asihpi, &hpi_ctl);
2574719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2575719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_MULTIPLEXER:
2576719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_mux_add(asihpi, &hpi_ctl);
2577719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2578719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_CHANNEL_MODE:
2579719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_cmode_add(asihpi, &hpi_ctl);
2580719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2581719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_METER:
2582719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex);
2583719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2584719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_SAMPLECLOCK:
2585719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_sampleclock_add(
2586719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						asihpi, &hpi_ctl);
2587719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2588719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_CONNECTION:	/* ignore these */
2589719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			continue;
2590719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_TUNER:
2591719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_tuner_add(asihpi, &hpi_ctl);
2592719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2593719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_AESEBU_TRANSMITTER:
2594719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl);
2595719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2596719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_AESEBU_RECEIVER:
2597719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl);
2598719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2599719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_VOX:
2600719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_BITSTREAM:
2601719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_MICROPHONE:
2602719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_PARAMETRIC_EQ:
2603719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_COMPANDER:
2604719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		default:
2605719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (mixer_dump)
2606719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				snd_printk(KERN_INFO
2607e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett					"Untranslated HPI Control"
2608719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					"(%d) %d %d %d %d %d\n",
2609719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					idx,
2610719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.control_type,
2611719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.src_node_type,
2612719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.src_node_index,
2613719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.dst_node_type,
2614719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.dst_node_index);
2615719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			continue;
2616719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		};
2617719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err < 0)
2618719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return err;
2619719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2620719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (HPI_ERROR_INVALID_OBJ_INDEX != err)
2621719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_handle_error(err);
2622719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2623719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printk(KERN_INFO "%d mixer controls found\n", idx);
2624719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2625719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2626719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2627719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2628719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2629719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   /proc interface
2630719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2631719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2632719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void
2633719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettsnd_asihpi_proc_read(struct snd_info_entry *entry,
2634719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			struct snd_info_buffer *buffer)
2635719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2636719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = entry->private_data;
2637719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 version;
2638719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
2639719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 rate = 0;
2640719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source = 0;
2641719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2642719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2643719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_iprintf(buffer, "ASIHPI driver proc file\n");
2644719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_iprintf(buffer,
2645719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		"adapter ID=%4X\n_index=%d\n"
2646719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		"num_outstreams=%d\n_num_instreams=%d\n",
2647719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->type, asihpi->adapter_index,
2648719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->num_outstreams, asihpi->num_instreams);
2649719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2650719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	version = asihpi->version;
2651719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_iprintf(buffer,
2652719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		"serial#=%d\n_hw version %c%d\nDSP code version %03d\n",
2653719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->serial_number, ((version >> 3) & 0xf) + 'A',
2654719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		version & 0x7,
2655719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		((version >> 13) * 100) + ((version >> 7) & 0x3f));
2656719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2657ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_mixer_get_control(asihpi->h_mixer,
2658719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2659719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_CONTROL_SAMPLECLOCK, &h_control);
2660719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2661719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err) {
2662ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_sample_clock_get_sample_rate(
2663719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					h_control, &rate);
2664ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err += hpi_sample_clock_get_source(h_control, &source);
2665719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2666719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err)
2667719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n",
2668719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			rate, sampleclock_sources[source]);
2669719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2670719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2671719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2672719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2673719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2674719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
2675719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2676719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_info_entry *entry;
2677719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2678719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!snd_card_proc_new(asihpi->card, "info", &entry))
2679719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_info_set_text_ops(entry, asihpi, snd_asihpi_proc_read);
2680719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2681719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2682719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2683719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   HWDEP
2684719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2685719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2686719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file)
2687719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2688719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (enable_hpi_hwdep)
2689719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return 0;
2690719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2691719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENODEV;
2692719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2693719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2694719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2695719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file)
2696719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2697719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (enable_hpi_hwdep)
2698719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return asihpi_hpi_release(file);
2699719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2700719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENODEV;
2701719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2702719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2703719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
2704719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				unsigned int cmd, unsigned long arg)
2705719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2706719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (enable_hpi_hwdep)
2707719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return asihpi_hpi_ioctl(file, cmd, arg);
2708719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2709719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENODEV;
2710719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2711719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2712719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2713719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* results in /dev/snd/hwC#D0 file for each card with index #
2714719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
2715719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
2716719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
2717719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int device, struct snd_hwdep **rhwdep)
2718719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2719719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_hwdep *hw;
2720719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2721719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2722719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (rhwdep)
2723719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		*rhwdep = NULL;
2724719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
2725719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
2726719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
2727719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	strcpy(hw->name, "asihpi (HPI)");
2728719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->iface = SNDRV_HWDEP_IFACE_LAST;
2729719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->ops.open = snd_asihpi_hpi_open;
2730719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->ops.ioctl = snd_asihpi_hpi_ioctl;
2731719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->ops.release = snd_asihpi_hpi_release;
2732719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->private_data = asihpi;
2733719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (rhwdep)
2734719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		*rhwdep = hw;
2735719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2736719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2737719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2738719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2739719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   CARD
2740719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2741719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
2742719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				       const struct pci_device_id *pci_id)
2743719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2744719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2745719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2746719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 version;
2747719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int pcm_substreams;
2748719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2749719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_adapter *hpi_card;
2750719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card;
2751719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi;
2752719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2753719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
2754719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_stream;
2755719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2756719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	static int dev;
2757719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (dev >= SNDRV_CARDS)
2758719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENODEV;
2759719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2760719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* Should this be enable[hpi_card->index] ? */
2761719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!enable[dev]) {
2762719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		dev++;
2763719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENOENT;
2764719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2765719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2766719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = asihpi_adapter_probe(pci_dev, pci_id);
2767719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
2768719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
2769719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2770719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_card = pci_get_drvdata(pci_dev);
2771719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* first try to give the card the same index as its hardware index */
2772719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_create(hpi_card->index,
2773719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      id[hpi_card->index], THIS_MODULE,
2774719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      sizeof(struct snd_card_asihpi),
2775719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      &card);
2776719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0) {
2777719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* if that fails, try the default index==next available */
2778719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err =
2779719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    snd_card_create(index[dev], id[dev],
2780719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    THIS_MODULE,
2781719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    sizeof(struct snd_card_asihpi),
2782719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    &card);
2783719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err < 0)
2784719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return err;
2785719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_printk(KERN_WARNING
2786e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			"**** WARNING **** Adapter index %d->ALSA index %d\n",
2787719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			hpi_card->index, card->number);
2788719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2789719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
27901225367a481ae751738630158c7ca96aa1c7bac8Eliot Blennerhassett	snd_card_set_dev(card, &pci_dev->dev);
27911225367a481ae751738630158c7ca96aa1c7bac8Eliot Blennerhassett
2792719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi = (struct snd_card_asihpi *) card->private_data;
2793719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi->card = card;
27941225367a481ae751738630158c7ca96aa1c7bac8Eliot Blennerhassett	asihpi->pci = pci_dev;
2795719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi->adapter_index = hpi_card->index;
2796ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_adapter_get_info(
2797719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 asihpi->adapter_index,
2798719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 &asihpi->num_outstreams,
2799719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 &asihpi->num_instreams,
2800719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 &asihpi->version,
2801719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 &asihpi->serial_number, &asihpi->type));
2802719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2803719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	version = asihpi->version;
2804719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d "
2805719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			"num_instreams=%d S/N=%d\n"
2806e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			"Hw Version %c%d DSP code version %03d\n",
2807719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->type, asihpi->adapter_index,
2808719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->num_outstreams,
2809719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->num_instreams, asihpi->serial_number,
2810719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			((version >> 3) & 0xf) + 'A',
2811719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			version & 0x7,
2812719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			((version >> 13) * 100) + ((version >> 7) & 0x3f));
2813719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2814719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcm_substreams = asihpi->num_outstreams;
2815719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (pcm_substreams < asihpi->num_instreams)
2816719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		pcm_substreams = asihpi->num_instreams;
2817719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2818ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_adapter_get_property(asihpi->adapter_index,
2819719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_ADAPTER_PROPERTY_CAPS1,
2820719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		NULL, &asihpi->support_grouping);
2821719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
2822719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->support_grouping = 0;
2823719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2824ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_adapter_get_property(asihpi->adapter_index,
2825719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_ADAPTER_PROPERTY_CAPS2,
2826719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		&asihpi->support_mrx, NULL);
2827719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
2828719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->support_mrx = 0;
2829719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2830ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_adapter_get_property(asihpi->adapter_index,
2831719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_ADAPTER_PROPERTY_INTERVAL,
2832719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		NULL, &asihpi->update_interval_frames);
2833719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
2834719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->update_interval_frames = 512;
2835719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2836f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	if (!asihpi->can_dma)
283726aebef420f8036213419b8a46e3a07db51439cdEliot Blennerhassett		asihpi->update_interval_frames *= 2;
283826aebef420f8036213419b8a46e3a07db51439cdEliot Blennerhassett
2839ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
2840719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			     0, &h_stream));
2841719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2842ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_instream_host_buffer_free(h_stream);
2843f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	asihpi->can_dma = (!err);
2844719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2845ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_close(h_stream));
2846719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2847ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_adapter_get_property(asihpi->adapter_index,
2848719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_ADAPTER_PROPERTY_CURCHANNELS,
2849719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		&asihpi->in_max_chans, &asihpi->out_max_chans);
2850719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err) {
2851719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->in_max_chans = 2;
2852719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->out_max_chans = 2;
2853719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2854719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2855f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n",
2856f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett			asihpi->can_dma,
2857719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->support_grouping,
2858719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->support_mrx
2859719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	      );
2860719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2861719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams);
2862719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0) {
2863719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_printk(KERN_ERR "pcm_new failed\n");
2864719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		goto __nodev;
2865719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2866719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_asihpi_mixer_new(asihpi);
2867719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0) {
2868719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_printk(KERN_ERR "mixer_new failed\n");
2869719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		goto __nodev;
2870719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2871719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2872ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_mixer_get_control(asihpi->h_mixer,
2873719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2874719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_CONTROL_SAMPLECLOCK, &h_control);
2875719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2876719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err)
2877719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = hpi_sample_clock_set_local_rate(
2878ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			h_control, adapter_fs);
2879719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2880719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_asihpi_proc_init(asihpi);
2881719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2882719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* always create, can be enabled or disabled dynamically
2883719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    by enable_hwdep  module param*/
2884719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_asihpi_hpi_new(asihpi, 0, NULL);
2885719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2886f3d145aac913b318e96e5c2763d8908805a5e30aEliot Blennerhassett	strcpy(card->driver, "ASIHPI");
2887719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2888719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
2889719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	sprintf(card->longname, "%s %i",
2890719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			card->shortname, asihpi->adapter_index);
2891719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_register(card);
2892b2e65c8e9133218eb28c30e79ddd3d66d4666ba0Eliot Blennerhassett
2893719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err) {
2894719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_card->snd_card_asihpi = card;
2895719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		dev++;
2896719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return 0;
2897719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2898719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett__nodev:
2899719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_free(card);
2900719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err);
2901719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return err;
2902719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2903719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2904719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2905719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void __devexit snd_asihpi_remove(struct pci_dev *pci_dev)
2906719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2907719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev);
2908719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2909719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_free(hpi_card->snd_card_asihpi);
2910719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_card->snd_card_asihpi = NULL;
2911719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi_adapter_remove(pci_dev);
2912719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2913719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2914719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = {
2915719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	{HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
2916719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2917719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		(kernel_ulong_t)HPI_6205},
2918719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	{HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
2919719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2920719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		(kernel_ulong_t)HPI_6000},
2921719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	{0,}
2922719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
2923719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
2924719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2925719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct pci_driver driver = {
2926719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.name = "asihpi",
2927719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.id_table = asihpi_pci_tbl,
2928719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.probe = snd_asihpi_probe,
2929719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.remove = __devexit_p(snd_asihpi_remove),
2930719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#ifdef CONFIG_PM
2931719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*	.suspend = snd_asihpi_suspend,
2932719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.resume = snd_asihpi_resume, */
2933719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
2934719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
2935719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2936719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __init snd_asihpi_init(void)
2937719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2938719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi_init();
2939719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return pci_register_driver(&driver);
2940719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2941719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2942719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void __exit snd_asihpi_exit(void)
2943719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2944719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2945719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pci_unregister_driver(&driver);
2946719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi_exit();
2947719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2948719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2949719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_init(snd_asihpi_init)
2950719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_exit(snd_asihpi_exit)
2951719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2952