asihpi.c revision c4ed97d9e7ec9b8c8453af4ce55497d85970426c
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/* >0: print Hw params, timer vars. >1: print stream write/copy sizes  */
26719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define REALLY_VERBOSE_LOGGING 0
27719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
28719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#if REALLY_VERBOSE_LOGGING
29719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define VPRINTK1 snd_printd
30719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#else
31719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define VPRINTK1(...)
32719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
33719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
34719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#if REALLY_VERBOSE_LOGGING > 1
35719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define VPRINTK2 snd_printd
36719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#else
37719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define VPRINTK2(...)
38719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
39719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
40719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include "hpi_internal.h"
41719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include "hpimsginit.h"
42719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include "hpioctl.h"
43719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
44719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/pci.h>
45e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett#include <linux/version.h>
46719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/init.h>
47719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/jiffies.h>
48719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/slab.h>
49719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/time.h>
50719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <linux/wait.h>
51719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/core.h>
52719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/control.h>
53719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/pcm.h>
54719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/pcm_params.h>
55719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/info.h>
56719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/initval.h>
57719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/tlv.h>
58719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#include <sound/hwdep.h>
59719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
60719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
61719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_LICENSE("GPL");
62719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
63719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
64719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
65719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* index 0-MAX */
66719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
67719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
68719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int enable_hpi_hwdep = 1;
69719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
70719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param_array(index, int, NULL, S_IRUGO);
71719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard.");
72719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
73719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param_array(id, charp, NULL, S_IRUGO);
74719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard.");
75719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
76719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param_array(enable, bool, NULL, S_IRUGO);
77719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard.");
78719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
79719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param(enable_hpi_hwdep, bool, S_IRUGO|S_IWUSR);
80719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(enable_hpi_hwdep,
81719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		"ALSA enable HPI hwdep for AudioScience soundcard ");
82719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
83719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* identify driver */
84719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#ifdef KERNEL_ALSA_BUILD
85e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettstatic char *build_info = "Built using headers from kernel source";
86719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param(build_info, charp, S_IRUGO);
87719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(build_info, "built using headers from kernel source");
88719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#else
89e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettstatic char *build_info = "Built within ALSA source";
90719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_param(build_info, charp, S_IRUGO);
91719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_PARM_DESC(build_info, "built within ALSA source");
92719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
93719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
94719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* set to 1 to dump every control from adapter to log */
95719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic const int mixer_dump;
96719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
97719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define DEFAULT_SAMPLERATE 44100
98719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int adapter_fs = DEFAULT_SAMPLERATE;
99719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
100719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* defaults */
101719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define PERIODS_MIN 2
102e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett#define PERIOD_BYTES_MIN  2048
103719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define BUFFER_BYTES_MAX (512 * 1024)
104719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
105ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett/* convert stream to character */
106ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C')
107ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
108719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*#define TIMER_MILLISECONDS 20
109719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000)
110719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
111719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
112719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
113719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
114719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct clk_source {
115719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int source;
116719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int index;
117719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	char *name;
118719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
119719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
120719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct clk_cache {
121719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int count;
122719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int has_local;
123719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_source s[MAX_CLOCKSOURCES];
124719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
125719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
126719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Per card data */
127719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct snd_card_asihpi {
128719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card;
129719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct pci_dev *pci;
130719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 adapter_index;
131719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 serial_number;
132719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 type;
133719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 version;
134719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 num_outstreams;
135719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 num_instreams;
136719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
137719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_mixer;
138719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache cc;
139719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
140719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 support_mmap;
141719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 support_grouping;
142719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 support_mrx;
143719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 update_interval_frames;
144719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 in_max_chans;
145719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 out_max_chans;
146719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
147719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
148719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Per stream data */
149719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct snd_card_asihpi_pcm {
150719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct timer_list timer;
151719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int respawn_timer;
152719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int hpi_buffer_attached;
153ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	unsigned int buffer_bytes;
154ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	unsigned int period_bytes;
155719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int bytes_per_sec;
156e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
157e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	unsigned int pcm_buf_dma_ofs;	/* DMA R/W offset in buffer */
158e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	unsigned int pcm_buf_elapsed_dma_ofs;	/* DMA R/W offset in buffer */
159719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_substream *substream;
160719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_stream;
161719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_format format;
162719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
163719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
164719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* universal stream verbs work with out or in stream handles */
165719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
166719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Functions to allow driver to give a buffer to HPI for busmastering */
167719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
168719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic u16 hpi_stream_host_buffer_attach(
169719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_stream,   /* handle to outstream. */
170719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 size_in_bytes, /* size in bytes of bus mastering buffer */
171719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 pci_address
172719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett)
173719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
174719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_message hm;
175719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_response hr;
176719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int obj = hpi_handle_object(h_stream);
177719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
178719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!h_stream)
179719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return HPI_ERROR_INVALID_OBJ;
180719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_init_message_response(&hm, &hr, obj,
181719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			obj == HPI_OBJ_OSTREAM ?
182719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_OSTREAM_HOSTBUFFER_ALLOC :
183719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_ISTREAM_HOSTBUFFER_ALLOC);
184719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
185719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_to_indexes(h_stream, &hm.adapter_index,
186719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hm.obj_index);
187719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
188719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hm.u.d.u.buffer.buffer_size = size_in_bytes;
189719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hm.u.d.u.buffer.pci_address = pci_address;
190719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER;
191719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_send_recv(&hm, &hr);
192719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return hr.error;
193719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
194719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
195ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic u16 hpi_stream_host_buffer_detach(u32  h_stream)
196719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
197719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_message hm;
198719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_response hr;
199719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int obj = hpi_handle_object(h_stream);
200719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
201719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!h_stream)
202719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return HPI_ERROR_INVALID_OBJ;
203719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
204719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_init_message_response(&hm, &hr,  obj,
205719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			obj == HPI_OBJ_OSTREAM ?
206719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_OSTREAM_HOSTBUFFER_FREE :
207719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_ISTREAM_HOSTBUFFER_FREE);
208719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
209719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_to_indexes(h_stream, &hm.adapter_index,
210719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hm.obj_index);
211719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER;
212719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_send_recv(&hm, &hr);
213719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return hr.error;
214719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
215719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
216ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_start(u32 h_stream)
217719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
218719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
219ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_start(h_stream);
220719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
221ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_start(h_stream);
222719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
223719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
224ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_stop(u32 h_stream)
225719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
226719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
227ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_stop(h_stream);
228719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
229ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_stop(h_stream);
230719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
231719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
232719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic inline u16 hpi_stream_get_info_ex(
233719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32 h_stream,
234719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u16        *pw_state,
235719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32        *pbuffer_size,
236719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32        *pdata_in_buffer,
237719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32        *psample_count,
238719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett    u32        *pauxiliary_data
239719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett)
240719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
241e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	u16 e;
242719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream)  ==  HPI_OBJ_OSTREAM)
243ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		e = hpi_outstream_get_info_ex(h_stream, pw_state,
244719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					pbuffer_size, pdata_in_buffer,
245719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					psample_count, pauxiliary_data);
246719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
247ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		e = hpi_instream_get_info_ex(h_stream, pw_state,
248719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					pbuffer_size, pdata_in_buffer,
249719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					psample_count, pauxiliary_data);
250e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	return e;
251719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
252719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
253ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_group_add(
254719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					u32 h_master,
255719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					u32 h_stream)
256719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
257719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_master) ==  HPI_OBJ_OSTREAM)
258ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_group_add(h_master, h_stream);
259719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
260ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_group_add(h_master, h_stream);
261719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
262719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
263ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_group_reset(u32 h_stream)
264719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
265719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
266ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_group_reset(h_stream);
267719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
268ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_group_reset(h_stream);
269719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
270719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
271ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic inline u16 hpi_stream_group_get_map(
272719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				u32 h_stream, u32 *mo, u32 *mi)
273719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
274719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
275ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_outstream_group_get_map(h_stream, mo, mi);
276719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
277ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		return hpi_instream_group_get_map(h_stream, mo, mi);
278719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
279719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
280719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic u16 handle_error(u16 err, int line, char *filename)
281719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
282719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
283719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		printk(KERN_WARNING
284719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			"in file %s, line %d: HPI error %d\n",
285719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			filename, line, err);
286719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return err;
287719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
288719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
289719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define hpi_handle_error(x)  handle_error(x, __LINE__, __FILE__)
290719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
291719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/***************************** GENERAL PCM ****************/
292719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#if REALLY_VERBOSE_LOGGING
293719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void print_hwparams(struct snd_pcm_hw_params *p)
294719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
295719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd("HWPARAMS \n");
296719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd("samplerate %d \n", params_rate(p));
297e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	snd_printd("Channels %d \n", params_channels(p));
298e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	snd_printd("Format %d \n", params_format(p));
299719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd("subformat %d \n", params_subformat(p));
300e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	snd_printd("Buffer bytes %d \n", params_buffer_bytes(p));
301e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	snd_printd("Period bytes %d \n", params_period_bytes(p));
302719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd("access %d \n", params_access(p));
303719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd("period_size %d \n", params_period_size(p));
304719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd("periods %d \n", params_periods(p));
305719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd("buffer_size %d \n", params_buffer_size(p));
306719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
307719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#else
308719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define print_hwparams(x)
309719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
310719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
311719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic snd_pcm_format_t hpi_to_alsa_formats[] = {
312719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* INVALID */
313719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_U8,	/* HPI_FORMAT_PCM8_UNSIGNED        1 */
314719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_S16,	/* HPI_FORMAT_PCM16_SIGNED         2 */
315719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_MPEG_L1              3 */
316719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_MPEG,	/* HPI_FORMAT_MPEG_L2              4 */
317719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_MPEG,	/* HPI_FORMAT_MPEG_L3              5 */
318719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_DOLBY_AC2            6 */
319719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_DOLBY_AC3            7 */
320719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN      8 */
321719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_AA_TAGIT1_HITS       9 */
322719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_AA_TAGIT1_INSERTS   10 */
323719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_S32,	/* HPI_FORMAT_PCM32_SIGNED        11 */
324719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_RAW_BITSTREAM       12 */
325719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1,			/* HPI_FORMAT_AA_TAGIT1_HITS_EX1  13 */
326719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	SNDRV_PCM_FORMAT_FLOAT,	/* HPI_FORMAT_PCM32_FLOAT         14 */
327719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#if 1
328719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* ALSA can't handle 3 byte sample size together with power-of-2
329719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 *  constraint on buffer_bytes, so disable this format
330719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 */
331719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	-1
332719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#else
333ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	/* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */
334719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
335719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
336719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
337719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
338719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,
339719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					   u16 *hpi_format)
340719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
341719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 format;
342719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
343719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (format = HPI_FORMAT_PCM8_UNSIGNED;
344719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	     format <= HPI_FORMAT_PCM24_SIGNED; format++) {
345719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (hpi_to_alsa_formats[format] == alsa_format) {
346719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			*hpi_format = format;
347719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return 0;
348719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
349719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
350719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
351719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd(KERN_WARNING "failed match for alsa format %d\n",
352719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   alsa_format);
353719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*hpi_format = 0;
354719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return -EINVAL;
355719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
356719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
357719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
358719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					 struct snd_pcm_hardware *pcmhw)
359719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
360719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
361719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
362719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 sample_rate;
363719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int idx;
364719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int rate_min = 200000;
365719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int rate_max = 0;
366719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int rates = 0;
367719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
368719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (asihpi->support_mrx) {
369719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		rates |= SNDRV_PCM_RATE_CONTINUOUS;
370719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		rates |= SNDRV_PCM_RATE_8000_96000;
371719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		rate_min = 8000;
372719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		rate_max = 100000;
373719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	} else {
374719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* on cards without SRC,
375719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   valid rates are determined by sampleclock */
376ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_mixer_get_control(asihpi->h_mixer,
377719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
378719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					  HPI_CONTROL_SAMPLECLOCK, &h_control);
379719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err) {
380719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			snd_printk(KERN_ERR
381e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				"No local sampleclock, err %d\n", err);
382719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
383719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
384719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		for (idx = 0; idx < 100; idx++) {
385ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (hpi_sample_clock_query_local_rate(
386719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				h_control, idx, &sample_rate)) {
387719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				if (!idx)
388719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					snd_printk(KERN_ERR
389e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett						"Local rate query failed\n");
390719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
391719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
392719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			}
393719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
394719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			rate_min = min(rate_min, sample_rate);
395719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			rate_max = max(rate_max, sample_rate);
396719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
397719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			switch (sample_rate) {
398719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 5512:
399719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_5512;
400719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
401719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 8000:
402719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_8000;
403719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
404719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 11025:
405719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_11025;
406719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
407719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 16000:
408719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_16000;
409719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
410719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 22050:
411719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_22050;
412719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
413719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 32000:
414719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_32000;
415719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
416719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 44100:
417719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_44100;
418719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
419719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 48000:
420719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_48000;
421719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
422719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 64000:
423719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_64000;
424719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
425719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 88200:
426719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_88200;
427719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
428719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 96000:
429719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_96000;
430719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
431719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 176400:
432719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_176400;
433719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
434719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			case 192000:
435719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_192000;
436719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
437719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			default: /* some other rate */
438719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				rates |= SNDRV_PCM_RATE_KNOT;
439719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			}
440719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
441719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
442719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
443719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* printk(KERN_INFO "Supported rates %X %d %d\n",
444719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   rates, rate_min, rate_max); */
445719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcmhw->rates = rates;
446719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcmhw->rate_min = rate_min;
447719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcmhw->rate_max = rate_max;
448719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
449719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
450719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
451719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					 struct snd_pcm_hw_params *params)
452719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
453719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
454719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
455719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
456719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
457719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 format;
458315e8f7501ad929acacfa94c251283e837f281edKulikov Vasiliy	int width;
459719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int bytes_per_sec;
460719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
461719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	print_hwparams(params);
462719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
463719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
464719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
465719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format);
466719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
467719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
468719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
469719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	VPRINTK1(KERN_INFO "format %d, %d chans, %d_hz\n",
470719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				format, params_channels(params),
471719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				params_rate(params));
472719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
473719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_error(hpi_format_create(&dpcm->format,
474719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			params_channels(params),
475719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			format, params_rate(params), 0, 0));
476719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
477719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
478ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (hpi_instream_reset(dpcm->h_stream) != 0)
479719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -EINVAL;
480719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
481ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (hpi_instream_set_format(
482719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			dpcm->h_stream, &dpcm->format) != 0)
483719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -EINVAL;
484719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
485719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
486719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->hpi_buffer_attached = 0;
487719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (card->support_mmap) {
488719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
489ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_stream_host_buffer_attach(dpcm->h_stream,
490719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			params_buffer_bytes(params),  runtime->dma_addr);
491719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err == 0) {
492ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			VPRINTK1(KERN_INFO
493719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				"stream_host_buffer_attach succeeded %u %lu\n",
494719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				params_buffer_bytes(params),
495719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				(unsigned long)runtime->dma_addr);
496719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		} else {
497719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			snd_printd(KERN_INFO
498719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					"stream_host_buffer_attach error %d\n",
499719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					err);
500719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -ENOMEM;
501719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
502719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
503ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
504719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						&dpcm->hpi_buffer_attached,
505719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						NULL, NULL, NULL);
506719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
507ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		VPRINTK1(KERN_INFO "stream_host_buffer_attach status 0x%x\n",
508719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				dpcm->hpi_buffer_attached);
509719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
510719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	bytes_per_sec = params_rate(params) * params_channels(params);
511315e8f7501ad929acacfa94c251283e837f281edKulikov Vasiliy	width = snd_pcm_format_width(params_format(params));
512315e8f7501ad929acacfa94c251283e837f281edKulikov Vasiliy	bytes_per_sec *= width;
513719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	bytes_per_sec /= 8;
514315e8f7501ad929acacfa94c251283e837f281edKulikov Vasiliy	if (width < 0 || bytes_per_sec == 0)
515719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
516719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
517719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->bytes_per_sec = bytes_per_sec;
518ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	dpcm->buffer_bytes = params_buffer_bytes(params);
519ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	dpcm->period_bytes = params_period_bytes(params);
520ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1(KERN_INFO "buffer_bytes=%d, period_bytes=%d, bps=%d\n",
521ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec);
522719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
523719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
524719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
525719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
526e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettstatic int
527e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettsnd_card_asihpi_hw_free(struct snd_pcm_substream *substream)
528e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett{
529e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
530e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
531e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	if (dpcm->hpi_buffer_attached)
532ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_stream_host_buffer_detach(dpcm->h_stream);
533e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
534e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	snd_pcm_lib_free_pages(substream);
535e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	return 0;
536e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett}
537e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
538e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettstatic void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)
539e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett{
540e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
541e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	kfree(dpcm);
542e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett}
543e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
544719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
545719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    substream)
546719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
547719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
548719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
549719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int expiry;
550719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
551ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	expiry = HZ / 200;
552ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	/*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */
553e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	expiry = max(expiry, 1); /* don't let it be zero! */
554719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.expires = jiffies + expiry;
555719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->respawn_timer = 1;
556719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	add_timer(&dpcm->timer);
557719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
558719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
559719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
560719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
561719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
562719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
563719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
564719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->respawn_timer = 0;
565719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	del_timer(&dpcm->timer);
566719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
567719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
568719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
569719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					   int cmd)
570719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
571719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
572719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
573719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_substream *s;
574719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 e;
575719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
576ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1(KERN_INFO "%c%d trigger\n",
577ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			SCHR(substream->stream), substream->number);
578719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	switch (cmd) {
579719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	case SNDRV_PCM_TRIGGER_START:
580719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_group_for_each_entry(s, substream) {
581e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			struct snd_pcm_runtime *runtime = s->runtime;
582e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			struct snd_card_asihpi_pcm *ds = runtime->private_data;
583719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
584719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (snd_pcm_substream_chip(s) != card)
585719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				continue;
586719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
587ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			/* don't link Cap and Play */
588ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (substream->stream != s->stream)
589ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				continue;
590ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
591719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
592719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				(card->support_mmap)) {
593719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				/* How do I know how much valid data is present
594e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				* in buffer? Must be at least one period!
595e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				* Guessing 2 periods, but if
596719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				* buffer is bigger it may contain even more
597719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				* data??
598719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				*/
599ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				unsigned int preload = ds->period_bytes * 1;
600ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				VPRINTK2(KERN_INFO "%d preload x%x\n", s->number, preload);
601719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				hpi_handle_error(hpi_outstream_write_buf(
602ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett						ds->h_stream,
603e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett						&runtime->dma_area[0],
604719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						preload,
605719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						&ds->format));
606e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				ds->pcm_buf_host_rw_ofs = preload;
607719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			}
608719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
609719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (card->support_grouping) {
610ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				VPRINTK1(KERN_INFO "\t%c%d group\n",
611ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett						SCHR(s->stream),
612719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						s->number);
613ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				e = hpi_stream_group_add(
614719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					dpcm->h_stream,
615719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					ds->h_stream);
616719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				if (!e) {
617719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					snd_pcm_trigger_done(s, substream);
618719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				} else {
619719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_handle_error(e);
620719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					break;
621719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				}
622719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} else
623719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
624719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
625ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		VPRINTK1(KERN_INFO "start\n");
626719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* start the master stream */
627719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_pcm_timer_start(substream);
628c4ed97d9e7ec9b8c8453af4ce55497d85970426cEliot Blennerhassett		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
629c4ed97d9e7ec9b8c8453af4ce55497d85970426cEliot Blennerhassett			!card->support_mmap)
630ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			hpi_handle_error(hpi_stream_start(dpcm->h_stream));
631719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		break;
632719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
633719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	case SNDRV_PCM_TRIGGER_STOP:
634719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_pcm_timer_stop(substream);
635719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_group_for_each_entry(s, substream) {
636719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (snd_pcm_substream_chip(s) != card)
637719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				continue;
638ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			/* don't link Cap and Play */
639ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (substream->stream != s->stream)
640ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				continue;
641719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
642719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			/*? workaround linked streams don't
643719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			transition to SETUP 20070706*/
644719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
645719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
646719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (card->support_grouping) {
647ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				VPRINTK1(KERN_INFO "\t%c%d group\n",
648ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				SCHR(s->stream),
649719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					s->number);
650719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				snd_pcm_trigger_done(s, substream);
651719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} else
652719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
653719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
654ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		VPRINTK1(KERN_INFO "stop\n");
655719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
656719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* _prepare and _hwparams reset the stream */
657ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
658719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
659719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			hpi_handle_error(
660ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				hpi_outstream_reset(dpcm->h_stream));
661719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
662719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (card->support_grouping)
663ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			hpi_handle_error(hpi_stream_group_reset(dpcm->h_stream));
664719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		break;
665719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
666719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
667ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		VPRINTK1(KERN_INFO "pause release\n");
668ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_stream_start(dpcm->h_stream));
669719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_pcm_timer_start(substream);
670719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		break;
671719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
672ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		VPRINTK1(KERN_INFO "pause\n");
673719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_pcm_timer_stop(substream);
674ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
675719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		break;
676719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	default:
677ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		snd_printd(KERN_ERR "\tINVALID\n");
678719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
679719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
680719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
681719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
682719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
683719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
684719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*algorithm outline
685719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett Without linking degenerates to getting single stream pos etc
686719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett Without mmap 2nd loop degenerates to snd_pcm_period_elapsed
687719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
688719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*
689e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassettpcm_buf_dma_ofs=get_buf_pos(s);
690719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettfor_each_linked_stream(s) {
691e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	pcm_buf_dma_ofs=get_buf_pos(s);
692ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	min_buf_pos = modulo_min(min_buf_pos, pcm_buf_dma_ofs, buffer_bytes)
693e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	new_data = min(new_data, calc_new_data(pcm_buf_dma_ofs,irq_pos)
694719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
695719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassetttimer.expires = jiffies + predict_next_period_ready(min_buf_pos);
696719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettfor_each_linked_stream(s) {
697e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	s->pcm_buf_dma_ofs = min_buf_pos;
698ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (new_data > period_bytes) {
699719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (mmap) {
700ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			irq_pos = (irq_pos + period_bytes) % buffer_bytes;
701719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (playback) {
702ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				write(period_bytes);
703719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} else {
704ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				read(period_bytes);
705719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			}
706719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
707719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_period_elapsed(s);
708719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
709719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
710719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
711719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
712719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/** Minimum of 2 modulo values.  Works correctly when the difference between
713719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett* the values is less than half the modulus
714719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
715719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic inline unsigned int modulo_min(unsigned int a, unsigned int b,
716719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					unsigned long int modulus)
717719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
718719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int result;
719719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (((a-b) % modulus) < (modulus/2))
720719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		result = b;
721719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
722719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		result = a;
723719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
724719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return result;
725719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
726719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
727719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/** Timer function, equivalent to interrupt service routine for cards
728719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
729719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_timer_function(unsigned long data)
730719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
731719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data;
732ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	struct snd_pcm_substream *substream = dpcm->substream;
733ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
734719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime;
735719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_substream *s;
736719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int newdata = 0;
737e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	unsigned int pcm_buf_dma_ofs, min_buf_pos = 0;
738719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int remdata, xfercount, next_jiffies;
739719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int first = 1;
740ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	int loops = 0;
741719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 state;
742e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
743719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
744ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1(KERN_INFO "%c%d snd_card_asihpi_timer_function\n",
745ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				SCHR(substream->stream), substream->number);
746ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
747719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* find minimum newdata and buffer pos in group */
748ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	snd_pcm_group_for_each_entry(s, substream) {
749719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
750719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		runtime = s->runtime;
751719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
752719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (snd_pcm_substream_chip(s) != card)
753719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			continue;
754719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
755ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		/* don't link Cap and Play */
756ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (substream->stream != s->stream)
757ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			continue;
758ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
759ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_stream_get_info_ex(
760719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					ds->h_stream, &state,
761e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett					&buffer_size, &bytes_avail,
762e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett					&samples_played, &on_card_bytes));
763719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
764719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* number of bytes in on-card buffer */
765e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		runtime->delay = on_card_bytes;
766719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
767ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
768e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
769ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (state == HPI_STATE_STOPPED) {
770ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				if ((bytes_avail == 0) &&
771ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				    (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
772ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_handle_error(hpi_stream_start(ds->h_stream));
773ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					VPRINTK1(KERN_INFO "P%d start\n", s->number);
774ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				}
775ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			} else if (state == HPI_STATE_DRAINED) {
776ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				VPRINTK1(KERN_WARNING "P%d drained\n",
777ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett						s->number);
778ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				/*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
779ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				continue; */
780ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			}
781ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		} else
782e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
783719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
784719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (first) {
785719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			/* can't statically init min when wrap is involved */
786e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			min_buf_pos = pcm_buf_dma_ofs;
787ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			newdata = (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes;
788719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			first = 0;
789719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		} else {
790719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			min_buf_pos =
791e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				modulo_min(min_buf_pos, pcm_buf_dma_ofs, UINT_MAX+1L);
792719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			newdata = min(
793ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				(pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes,
794719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				newdata);
795719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
796719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
797ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		VPRINTK1(KERN_INFO "PB timer hw_ptr x%04lX, appl_ptr x%04lX\n",
798719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(unsigned long)frames_to_bytes(runtime,
799719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						runtime->status->hw_ptr),
800719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(unsigned long)frames_to_bytes(runtime,
801719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						runtime->control->appl_ptr));
802e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
803ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		VPRINTK1(KERN_INFO "%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X,"
804ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			" aux=x%04X space=x%04X\n",
805ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			loops, SCHR(s->stream),	s->number,
806e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			state,	ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail,
807e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			(int)on_card_bytes, buffer_size-bytes_avail);
808ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		loops++;
809719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
810e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	pcm_buf_dma_ofs = min_buf_pos;
811719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
812ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	remdata = newdata % dpcm->period_bytes;
813ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	xfercount = newdata - remdata; /* a multiple of period_bytes */
814e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	/* come back when on_card_bytes has decreased enough to allow
815e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	   write to happen, or when data has been consumed to make another
816e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	   period
817e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	*/
818ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (xfercount && (on_card_bytes  > dpcm->period_bytes))
819ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		next_jiffies = ((on_card_bytes - dpcm->period_bytes) * HZ / dpcm->bytes_per_sec);
820e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	else
821ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		next_jiffies = ((dpcm->period_bytes - remdata) * HZ / dpcm->bytes_per_sec);
822e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
823e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	next_jiffies = max(next_jiffies, 1U);
824719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.expires = jiffies + next_jiffies;
825ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1(KERN_INFO "jif %d buf pos x%04X newdata x%04X xfer x%04X\n",
826e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
827e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
828ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	snd_pcm_group_for_each_entry(s, substream) {
829719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
830719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
831ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		/* don't link Cap and Play */
832ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (substream->stream != s->stream)
833ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			continue;
834ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett
835e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
836e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
837ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (xfercount && (on_card_bytes <= ds->period_bytes)) {
838719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (card->support_mmap) {
839719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
840ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					VPRINTK2(KERN_INFO "P%d write x%04x\n",
841719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							s->number,
842ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett							ds->period_bytes);
843719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_handle_error(
844719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						hpi_outstream_write_buf(
845ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett							ds->h_stream,
846719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							&s->runtime->
847719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett								dma_area[0],
848719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							xfercount,
849719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							&ds->format));
850719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				} else {
851ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					VPRINTK2(KERN_INFO "C%d read x%04x\n",
852719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						s->number,
853e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett						xfercount);
854719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_handle_error(
855719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						hpi_instream_read_buf(
856ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett							ds->h_stream,
857719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							NULL, xfercount));
858719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				}
859e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
860719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} /* else R/W will be handled by read/write callbacks */
861e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
862719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			snd_pcm_period_elapsed(s);
863719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
864719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
865719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
866719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (dpcm->respawn_timer)
867719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		add_timer(&dpcm->timer);
868719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
869719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
870719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/***************************** PLAYBACK OPS ****************/
871719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
872719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					  unsigned int cmd, void *arg)
873719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
874719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* snd_printd(KERN_INFO "Playback ioctl %d\n", cmd); */
875719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_pcm_lib_ioctl(substream, cmd, arg);
876719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
877719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
878719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
879719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    substream)
880719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
881719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
882719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
883719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
884ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1(KERN_INFO "playback prepare %d\n", substream->number);
885719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
886ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
887e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_host_rw_ofs = 0;
888e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_dma_ofs = 0;
889e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_elapsed_dma_ofs = 0;
890719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
891719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
892719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
893719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic snd_pcm_uframes_t
894719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettsnd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
895719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
896719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
897719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
898719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_uframes_t ptr;
899719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
900ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs  % dpcm->buffer_bytes);
901ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	/* VPRINTK2(KERN_INFO "playback_pointer=x%04lx\n", (unsigned long)ptr); */
902719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ptr;
903719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
904719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
905719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
906719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						u32 h_stream,
907719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						struct snd_pcm_hardware *pcmhw)
908719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
909719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_format hpi_format;
910719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 format;
911719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
912719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
913719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 sample_rate = 48000;
914719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
915719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* on cards without SRC, must query at valid rate,
916719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	* maybe set by external sync
917719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
918ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_mixer_get_control(asihpi->h_mixer,
919719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
920719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_CONTROL_SAMPLECLOCK, &h_control);
921719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
922719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err)
923ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_sample_clock_get_sample_rate(h_control,
924719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&sample_rate);
925719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
926719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (format = HPI_FORMAT_PCM8_UNSIGNED;
927719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	     format <= HPI_FORMAT_PCM24_SIGNED; format++) {
928719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = hpi_format_create(&hpi_format,
929719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					2, format, sample_rate, 128000, 0);
930719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err)
931ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			err = hpi_outstream_query_format(h_stream,
932719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett							&hpi_format);
933719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err && (hpi_to_alsa_formats[format] != -1))
934719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			pcmhw->formats |=
935719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				(1ULL << hpi_to_alsa_formats[format]);
936719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
937719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
938719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
939719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_hardware snd_card_asihpi_playback = {
940719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.channels_min = 1,
941719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.channels_max = 2,
942719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.buffer_bytes_max = BUFFER_BYTES_MAX,
943719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.period_bytes_min = PERIOD_BYTES_MIN,
944719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
945719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.periods_min = PERIODS_MIN,
946719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
947719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.fifo_size = 0,
948719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
949719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
950719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
951719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
952719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
953719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm;
954719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
955719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
956719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
957719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
958719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (dpcm == NULL)
959719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENOMEM;
960719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
961719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err =
962ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_outstream_open(card->adapter_index,
963719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      substream->number, &dpcm->h_stream);
964719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_error(err);
965719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
966719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		kfree(dpcm);
967719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
968719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EBUSY;
969719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
970719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EIO;
971719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
972719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*? also check ASI5000 samplerate source
973719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    If external, only support external rate.
974719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    If internal and other stream playing, cant switch
975719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
976719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
977719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	init_timer(&dpcm->timer);
978719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.data = (unsigned long) dpcm;
979719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.function = snd_card_asihpi_timer_function;
980719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->substream = substream;
981719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->private_data = dpcm;
982719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->private_free = snd_card_asihpi_runtime_free;
983719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
984719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_playback.channels_max = card->out_max_chans;
985719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*?snd_card_asihpi_playback.period_bytes_min =
986719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	card->out_max_chans * 4096; */
987719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
988719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_playback_format(card, dpcm->h_stream,
989719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					&snd_card_asihpi_playback);
990719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
991719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_playback);
992719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
993719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED |
994719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_INFO_DOUBLE |
995719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_INFO_BATCH |
996719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_INFO_BLOCK_TRANSFER |
997719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_INFO_PAUSE;
998719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
999719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (card->support_mmap)
1000719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP |
1001719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						SNDRV_PCM_INFO_MMAP_VALID;
1002719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1003719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (card->support_grouping)
1004719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
1005719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1006719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* struct is copied, so can create initializer dynamically */
1007719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->hw = snd_card_asihpi_playback;
1008719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1009719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (card->support_mmap)
1010719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = snd_pcm_hw_constraint_pow2(runtime, 0,
1011719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1012719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
1013719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
1014719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1015719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1016719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		card->update_interval_frames);
1017719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1018e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		card->update_interval_frames * 2, UINT_MAX);
1019719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1020719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_set_sync(substream);
1021719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1022ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1(KERN_INFO "playback open\n");
1023719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1024719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1025719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1026719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1027719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
1028719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1029719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1030719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1031719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1032ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_outstream_close(dpcm->h_stream));
1033ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1(KERN_INFO "playback close\n");
1034719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1035719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1036719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1037719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1038719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
1039719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					int channel,
1040719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					snd_pcm_uframes_t pos,
1041719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					void __user *src,
1042719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					snd_pcm_uframes_t count)
1043719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1044719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1045719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1046719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int len;
1047719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1048719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	len = frames_to_bytes(runtime, count);
1049719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1050719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (copy_from_user(runtime->dma_area, src, len))
1051719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EFAULT;
1052719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1053719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	VPRINTK2(KERN_DEBUG "playback copy%d %u bytes\n",
1054719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			substream->number, len);
1055719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1056ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
1057719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				runtime->dma_area, len, &dpcm->format));
1058719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1059e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
1060e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
1061719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1062719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1063719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1064719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
1065719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    substream, int channel,
1066719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    snd_pcm_uframes_t pos,
1067719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    snd_pcm_uframes_t count)
1068719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1069719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int len;
1070719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1071719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1072719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1073719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	len = frames_to_bytes(runtime, count);
1074ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1(KERN_INFO "playback silence  %u bytes\n", len);
1075719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1076719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	memset(runtime->dma_area, 0, len);
1077ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
1078719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				runtime->dma_area, len, &dpcm->format));
1079719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1080719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1081719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1082719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_ops snd_card_asihpi_playback_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	.copy = snd_card_asihpi_playback_copy,
1092719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.silence = snd_card_asihpi_playback_silence,
1093719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1094719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1095719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
1096719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.open = snd_card_asihpi_playback_open,
1097719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.close = snd_card_asihpi_playback_close,
1098719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.ioctl = snd_card_asihpi_playback_ioctl,
1099719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_params = snd_card_asihpi_pcm_hw_params,
1100719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_free = snd_card_asihpi_hw_free,
1101719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.prepare = snd_card_asihpi_playback_prepare,
1102719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.trigger = snd_card_asihpi_trigger,
1103719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.pointer = snd_card_asihpi_playback_pointer,
1104719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1105719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1106719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/***************************** CAPTURE OPS ****************/
1107719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic snd_pcm_uframes_t
1108719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettsnd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
1109719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1110719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1111719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1112719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1113ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK2(KERN_INFO "capture pointer %d=%d\n",
1114e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			substream->number, dpcm->pcm_buf_dma_ofs);
1115e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	/* NOTE Unlike playback can't use actual samples_played
1116719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		for the capture position, because those samples aren't yet in
1117719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		the local buffer available for reading.
1118719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1119ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	return bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
1120719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1121719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1122719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_ioctl(struct snd_pcm_substream *substream,
1123719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					 unsigned int cmd, void *arg)
1124719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1125719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_pcm_lib_ioctl(substream, cmd, arg);
1126719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1127719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1128719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
1129719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1130719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1131719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1132719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1133ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_reset(dpcm->h_stream));
1134e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_host_rw_ofs = 0;
1135e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_dma_ofs = 0;
1136e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_elapsed_dma_ofs = 0;
1137719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1138ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1("Capture Prepare %d\n", substream->number);
1139719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1140719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1141719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1142719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1143719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1144719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
1145719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					u32 h_stream,
1146719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					 struct snd_pcm_hardware *pcmhw)
1147719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1148719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett  struct hpi_format hpi_format;
1149719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 format;
1150719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1151719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
1152719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 sample_rate = 48000;
1153719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1154719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* on cards without SRC, must query at valid rate,
1155719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		maybe set by external sync */
1156ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_mixer_get_control(asihpi->h_mixer,
1157719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
1158719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_CONTROL_SAMPLECLOCK, &h_control);
1159719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1160719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err)
1161ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_sample_clock_get_sample_rate(h_control,
1162719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			&sample_rate);
1163719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1164719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (format = HPI_FORMAT_PCM8_UNSIGNED;
1165719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		format <= HPI_FORMAT_PCM24_SIGNED; format++) {
1166719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1167719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = hpi_format_create(&hpi_format, 2, format,
1168719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				sample_rate, 128000, 0);
1169719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err)
1170ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			err = hpi_instream_query_format(h_stream,
1171719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    &hpi_format);
1172719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err)
1173719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			pcmhw->formats |=
1174719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				(1ULL << hpi_to_alsa_formats[format]);
1175719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1176719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1177719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1178719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1179719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_hardware snd_card_asihpi_capture = {
1180719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.channels_min = 1,
1181719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.channels_max = 2,
1182719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.buffer_bytes_max = BUFFER_BYTES_MAX,
1183719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.period_bytes_min = PERIOD_BYTES_MIN,
1184719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
1185719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.periods_min = PERIODS_MIN,
1186719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
1187719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.fifo_size = 0,
1188719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1189719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1190719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
1191719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1192719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1193719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
1194719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm;
1195719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
1196719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1197719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
1198719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (dpcm == NULL)
1199719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENOMEM;
1200719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1201ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK1("hpi_instream_open adapter %d stream %d\n",
1202719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   card->adapter_index, substream->number);
1203719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1204719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = hpi_handle_error(
1205ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_instream_open(card->adapter_index,
1206719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			     substream->number, &dpcm->h_stream));
1207719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
1208719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		kfree(dpcm);
1209719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
1210719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EBUSY;
1211719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
1212719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EIO;
1213719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1214719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1215719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	init_timer(&dpcm->timer);
1216719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.data = (unsigned long) dpcm;
1217719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->timer.function = snd_card_asihpi_timer_function;
1218719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	dpcm->substream = substream;
1219719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->private_data = dpcm;
1220719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->private_free = snd_card_asihpi_runtime_free;
1221719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1222719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_capture.channels_max = card->in_max_chans;
1223719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_capture_format(card, dpcm->h_stream,
1224719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				       &snd_card_asihpi_capture);
1225719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_capture);
1226719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED;
1227719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1228719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (card->support_mmap)
1229719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
1230719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						SNDRV_PCM_INFO_MMAP_VALID;
1231719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1232e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	if (card->support_grouping)
1233e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
1234e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
1235719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	runtime->hw = snd_card_asihpi_capture;
1236719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1237719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (card->support_mmap)
1238719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = snd_pcm_hw_constraint_pow2(runtime, 0,
1239719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1240719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
1241719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
1242719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1243719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1244719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		card->update_interval_frames);
1245719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1246719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		card->update_interval_frames * 2, UINT_MAX);
1247719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1248719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_set_sync(substream);
1249719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1250719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1251719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1252719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1253719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
1254719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1255719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
1256719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1257ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_close(dpcm->h_stream));
1258719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1259719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1260719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1261719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
1262719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				int channel, snd_pcm_uframes_t pos,
1263719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				void __user *dst, snd_pcm_uframes_t count)
1264719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1265719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm_runtime *runtime = substream->runtime;
1266719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1267e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	u32 len;
1268719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1269e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	len = frames_to_bytes(runtime, count);
1270719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1271ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	VPRINTK2(KERN_INFO "capture copy%d %d bytes\n", substream->number, len);
1272ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream,
1273e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett				runtime->dma_area, len));
1274719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1275e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
1276719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1277e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	if (copy_to_user(dst, runtime->dma_area, len))
1278719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EFAULT;
1279719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1280719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1281719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1282719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1283719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
1284719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.open = snd_card_asihpi_capture_open,
1285719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.close = snd_card_asihpi_capture_close,
1286719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.ioctl = snd_card_asihpi_capture_ioctl,
1287719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_params = snd_card_asihpi_pcm_hw_params,
1288719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_free = snd_card_asihpi_hw_free,
1289719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.prepare = snd_card_asihpi_capture_prepare,
1290719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.trigger = snd_card_asihpi_trigger,
1291719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.pointer = snd_card_asihpi_capture_pointer,
1292719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1293719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1294719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct snd_pcm_ops snd_card_asihpi_capture_ops = {
1295719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.open = snd_card_asihpi_capture_open,
1296719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.close = snd_card_asihpi_capture_close,
1297719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.ioctl = snd_card_asihpi_capture_ioctl,
1298719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_params = snd_card_asihpi_pcm_hw_params,
1299719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.hw_free = snd_card_asihpi_hw_free,
1300719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.prepare = snd_card_asihpi_capture_prepare,
1301719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.trigger = snd_card_asihpi_trigger,
1302719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.pointer = snd_card_asihpi_capture_pointer,
1303719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.copy = snd_card_asihpi_capture_copy
1304719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1305719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1306719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
1307719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				      int device, int substreams)
1308719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1309719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_pcm *pcm;
1310719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
1311719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1312e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,
1313719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			 asihpi->num_outstreams, asihpi->num_instreams,
1314719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			 &pcm);
1315719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
1316719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
1317719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* pointer to ops struct is stored, dont change ops afterwards! */
1318719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (asihpi->support_mmap) {
1319719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1320719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&snd_card_asihpi_playback_mmap_ops);
1321719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1322719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&snd_card_asihpi_capture_mmap_ops);
1323719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	} else {
1324719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1325719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&snd_card_asihpi_playback_ops);
1326719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1327719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&snd_card_asihpi_capture_ops);
1328719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1329719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1330719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcm->private_data = asihpi;
1331719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcm->info_flags = 0;
1332e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	strcpy(pcm->name, "Asihpi PCM");
1333719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1334719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*? do we want to emulate MMAP for non-BBM cards?
1335719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
1336719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1337719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						snd_dma_pci_data(asihpi->pci),
1338719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						64*1024, BUFFER_BYTES_MAX);
1339719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1340719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1341719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1342719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1343719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/***************************** MIXER CONTROLS ****************/
1344719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstruct hpi_control {
1345719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
1346719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 control_type;
1347719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 src_node_type;
1348719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 src_node_index;
1349719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 dst_node_type;
1350719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 dst_node_index;
1351719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 band;
1352719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
1353719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1354719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1355ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic const char * const asihpi_tuner_band_names[] = {
1356719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"invalid",
1357719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"AM",
1358719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"FM mono",
1359719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV NTSC-M",
1360719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"FM stereo",
1361719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"AUX",
1362719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV PAL BG",
1363719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV PAL I",
1364719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV PAL DK",
1365719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"TV SECAM",
1366719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1367719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1368719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettcompile_time_assert(
1369719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	(ARRAY_SIZE(asihpi_tuner_band_names) ==
1370719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		(HPI_TUNER_BAND_LAST+1)),
1371719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	assert_tuner_band_names_size);
1372719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1373ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic const char * const asihpi_src_names[] = {
1374719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"no source",
1375e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"PCM",
1376e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Line",
1377e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Digital",
1378e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Tuner",
1379719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"RF",
1380e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Clock",
1381e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Bitstream",
1382e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Microphone",
1383e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Cobranet",
1384e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Analog",
1385e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Adapter",
1386719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1387719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1388719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettcompile_time_assert(
1389719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	(ARRAY_SIZE(asihpi_src_names) ==
1390168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		(HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
1391719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	assert_src_names_size);
1392719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1393ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic const char * const asihpi_dst_names[] = {
1394719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"no destination",
1395e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"PCM",
1396e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Line",
1397e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Digital",
1398719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	"RF",
1399e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Speaker",
1400e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Cobranet Out",
1401e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	"Analog"
1402719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
1403719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1404719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettcompile_time_assert(
1405719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	(ARRAY_SIZE(asihpi_dst_names) ==
1406168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		(HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
1407719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	assert_dst_names_size);
1408719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1409719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
1410719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_card_asihpi *asihpi)
1411719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1412719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
1413719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1414719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi));
1415719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
1416719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
1417719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else if (mixer_dump)
1418719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index);
1419719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1420719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1421719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1422719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1423719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Convert HPI control name and location into ALSA control name */
1424719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
1425719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct hpi_control *hpi_ctl,
1426719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				char *name)
1427719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1428e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	char *dir = "";
1429719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	memset(snd_control, 0, sizeof(*snd_control));
1430719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control->name = hpi_ctl->name;
1431719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control->private_value = hpi_ctl->h_control;
1432719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1433719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control->index = 0;
1434719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1435e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
1436e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir = "Capture ";  /* On or towards a PCM capture destination*/
1437e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1438e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		(!hpi_ctl->dst_node_type))
1439e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir = "Capture "; /* On a source node that is not PCM playback */
1440ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	else if (hpi_ctl->src_node_type &&
1441ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		(hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1442e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		(hpi_ctl->dst_node_type))
1443e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir = "Monitor Playback "; /* Between an input and an output */
1444e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	else
1445e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir = "Playback "; /* PCM Playback source, or  output node */
1446e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett
1447719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
1448e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		sprintf(hpi_ctl->name, "%s%d %s%d %s%s",
1449719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi_src_names[hpi_ctl->src_node_type],
1450719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			hpi_ctl->src_node_index,
1451719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi_dst_names[hpi_ctl->dst_node_type],
1452719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			hpi_ctl->dst_node_index,
1453e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			dir, name);
1454719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else if (hpi_ctl->dst_node_type) {
1455e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		sprintf(hpi_ctl->name, "%s %d %s%s",
1456719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi_dst_names[hpi_ctl->dst_node_type],
1457719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_ctl->dst_node_index,
1458e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir, name);
1459719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	} else {
1460e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		sprintf(hpi_ctl->name, "%s %d %s%s",
1461719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi_src_names[hpi_ctl->src_node_type],
1462719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_ctl->src_node_index,
1463e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		dir, name);
1464719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1465ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	/* printk(KERN_INFO "Adding %s %d to %d ",  hpi_ctl->name,
1466ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */
1467719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1468719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1469719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
1470719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Volume controls
1471719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
1472719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#define VOL_STEP_mB 1
1473719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
1474719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1475719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1476719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1477719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1478719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* native gains are in millibels */
1479719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short min_gain_mB;
1480719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short max_gain_mB;
1481719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short step_gain_mB;
1482719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1483ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_volume_query_range(h_control,
1484719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			&min_gain_mB, &max_gain_mB, &step_gain_mB);
1485719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err) {
1486719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		max_gain_mB = 0;
1487719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		min_gain_mB = -10000;
1488719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		step_gain_mB = VOL_STEP_mB;
1489719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1490719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1491719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1492719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 2;
1493719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;
1494719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;
1495719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;
1496719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1497719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1498719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1499719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
1500719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1501719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1502719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1503719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS];
1504719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1505ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_volume_get_gain(h_control, an_gain_mB));
1506719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;
1507719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;
1508719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1509719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1510719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1511719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1512719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
1513719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1514719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1515719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
1516719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1517719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS];
1518719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1519719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	an_gain_mB[0] =
1520719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    (ucontrol->value.integer.value[0]) * VOL_STEP_mB;
1521719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	an_gain_mB[1] =
1522719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    (ucontrol->value.integer.value[1]) * VOL_STEP_mB;
1523719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*  change = asihpi->mixer_volume[addr][0] != left ||
1524719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   asihpi->mixer_volume[addr][1] != right;
1525719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 */
1526719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
1527ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
1528719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
1529719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1530719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1531719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
1532719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1533719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
1534719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1535719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1536719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1537719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1538719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1539e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
1540719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1541719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1542719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_volume_info;
1543719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_volume_get;
1544719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_volume_put;
1545719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.tlv.p = db_scale_100;
1546719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1547719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1548719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1549719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1550719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
1551719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Level controls
1552719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
1553719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,
1554719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_info *uinfo)
1555719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1556719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1557719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1558719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short min_gain_mB;
1559719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short max_gain_mB;
1560719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short step_gain_mB;
1561719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1562719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err =
1563ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_level_query_range(h_control, &min_gain_mB,
1564719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			       &max_gain_mB, &step_gain_mB);
1565719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err) {
1566719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		max_gain_mB = 2400;
1567719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		min_gain_mB = -1000;
1568719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		step_gain_mB = 100;
1569719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1570719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1571719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1572719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 2;
1573719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB;
1574719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB;
1575719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB;
1576719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1577719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1578719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1579719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,
1580719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
1581719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1582719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1583719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS];
1584719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1585ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_level_get_gain(h_control, an_gain_mB));
1586719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] =
1587719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    an_gain_mB[0] / HPI_UNITS_PER_dB;
1588719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[1] =
1589719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    an_gain_mB[1] / HPI_UNITS_PER_dB;
1590719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1591719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1592719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1593719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1594719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,
1595719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
1596719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1597719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
1598719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1599719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS];
1600719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1601719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	an_gain_mB[0] =
1602719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1603719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	an_gain_mB[1] =
1604719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB;
1605719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*  change = asihpi->mixer_level[addr][0] != left ||
1606719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   asihpi->mixer_level[addr][1] != right;
1607719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 */
1608719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
1609ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_level_set_gain(h_control, an_gain_mB));
1610719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
1611719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1612719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1613719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0);
1614719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1615719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
1616719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1617719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1618719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1619719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1620719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1621719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* can't use 'volume' cos some nodes have volume as well */
1622e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Level");
1623719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1624719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1625719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_level_info;
1626719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_level_get;
1627719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_level_put;
1628719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.tlv.p = db_scale_level;
1629719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1630719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1631719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1632719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1633719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
1634719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   AESEBU controls
1635719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
1636719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1637719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* AESEBU format */
1638ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic const char * const asihpi_aesebu_format_names[] = {
1639ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"N/A", "S/PDIF", "AES/EBU" };
1640719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1641719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
1642719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1643719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1644719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1645719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1646719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.enumerated.items = 3;
1647719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1648719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1649719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		uinfo->value.enumerated.item =
1650719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			uinfo->value.enumerated.items - 1;
1651719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1652719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	strcpy(uinfo->value.enumerated.name,
1653719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
1654719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1655719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1656719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1657719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1658719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
1659719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			struct snd_ctl_elem_value *ucontrol,
1660ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			u16 (*func)(u32, u16 *))
1661719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1662719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1663719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source, err;
1664719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1665ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = func(h_control, &source);
1666719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1667719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* default to N/A */
1668719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = 0;
1669719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* return success but set the control to N/A */
1670719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
1671719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return 0;
1672719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (source == HPI_AESEBU_FORMAT_SPDIF)
1673719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.enumerated.item[0] = 1;
1674719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (source == HPI_AESEBU_FORMAT_AESEBU)
1675719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.enumerated.item[0] = 2;
1676719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1677719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1678719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1679719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1680719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
1681719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			struct snd_ctl_elem_value *ucontrol,
1682ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			 u16 (*func)(u32, u16))
1683719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1684719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1685719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1686719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* default to S/PDIF */
1687719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source = HPI_AESEBU_FORMAT_SPDIF;
1688719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1689719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ucontrol->value.enumerated.item[0] == 1)
1690719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		source = HPI_AESEBU_FORMAT_SPDIF;
1691719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ucontrol->value.enumerated.item[0] == 2)
1692719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		source = HPI_AESEBU_FORMAT_AESEBU;
1693719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1694ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (func(h_control, source) != 0)
1695719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
1696719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1697719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 1;
1698719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1699719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1700719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,
1701719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1702719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
1703ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_aesebu_receiver_get_format);
1704719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1705719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1706719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,
1707719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1708719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
1709ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_aesebu_receiver_set_format);
1710719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1711719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1712719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol,
1713719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1714719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1715719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1716719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1717719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1718719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = 0;
1719719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = 0X1F;
1720719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = 1;
1721719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1722719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1723719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1724719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1725719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,
1726719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1727719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1728719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1729719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 status;
1730719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1731ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_aesebu_receiver_get_error_status(
1732ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					 h_control, &status));
1733719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] = status;
1734719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1735719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1736719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1737719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
1738719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1739719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1740719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1741719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1742719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1743e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
1744719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1745719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_aesebu_format_info;
1746719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_aesebu_rx_format_get;
1747719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_aesebu_rx_format_put;
1748719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1749719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1750719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ctl_add(card, &snd_control, asihpi) < 0)
1751719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
1752719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1753e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Status");
1754719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access =
1755719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
1756719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_aesebu_rxstatus_info;
1757719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_aesebu_rxstatus_get;
1758719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1759719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1760719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1761719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1762719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,
1763719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1764719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
1765ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_aesebu_transmitter_get_format);
1766719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1767719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1768719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,
1769719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol) {
1770719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
1771ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett					hpi_aesebu_transmitter_set_format);
1772719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1773719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1774719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1775719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,
1776719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
1777719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1778719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
1779719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
1780719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1781e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
1782719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1783719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_aesebu_format_info;
1784719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_aesebu_tx_format_get;
1785719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_aesebu_tx_format_put;
1786719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1787719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
1788719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1789719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1790719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
1791719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Tuner controls
1792719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
1793719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1794719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Gain */
1795719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1796719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,
1797719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1798719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1799719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1800719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1801719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short idx;
1802719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 gain_range[3];
1803719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1804719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (idx = 0; idx < 3; idx++) {
1805ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_tuner_query_gain(h_control,
1806719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					  idx, &gain_range[idx]);
1807719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err != 0)
1808719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return err;
1809719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1810719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1811719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1812719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1813719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB;
1814719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB;
1815719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB;
1816719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1817719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1818719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1819719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,
1820719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1821719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1822719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*
1823719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1824719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1825719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1826719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short gain;
1827719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1828ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_get_gain(h_control, &gain));
1829719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
1830719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1831719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1832719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1833719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1834719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,
1835719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1836719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1837719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*
1838719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1839719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1840719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1841719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short gain;
1842719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1843719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1844ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_set_gain(h_control, gain));
1845719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1846719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 1;
1847719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1848719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1849719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Band  */
1850719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1851719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,
1852719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					u16 *band_list, u32 len) {
1853719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1854719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err = 0;
1855719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 i;
1856719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1857719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i < len; i++) {
1858ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_tuner_query_band(
1859719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				h_control, i, &band_list[i]);
1860719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err != 0)
1861719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
1862719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1863719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1864719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX))
1865719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EIO;
1866719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1867719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return i;
1868719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1869719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1870719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
1871719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1872719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1873719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 tuner_bands[HPI_TUNER_BAND_LAST];
1874719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int num_bands = 0;
1875719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1876719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1877719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_TUNER_BAND_LAST);
1878719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1879719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (num_bands < 0)
1880719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return num_bands;
1881719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1882719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1883719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1884719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.enumerated.items = num_bands;
1885719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1886719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (num_bands > 0) {
1887719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (uinfo->value.enumerated.item >=
1888719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					uinfo->value.enumerated.items)
1889719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			uinfo->value.enumerated.item =
1890719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				uinfo->value.enumerated.items - 1;
1891719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1892719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		strcpy(uinfo->value.enumerated.name,
1893719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi_tuner_band_names[
1894719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				tuner_bands[uinfo->value.enumerated.item]]);
1895719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1896719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1897719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1898719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1899719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1900719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
1901719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1902719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1903719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1904719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*
1905719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1906719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1907719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 band, idx;
1908719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 tuner_bands[HPI_TUNER_BAND_LAST];
1909719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 num_bands = 0;
1910719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1911719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1912719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_TUNER_BAND_LAST);
1913719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1914ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_get_band(h_control, &band));
1915719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1916719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = -1;
1917719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
1918719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (tuner_bands[idx] == band) {
1919719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.enumerated.item[0] = idx;
1920719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
1921719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
1922719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1923719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1924719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1925719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1926719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
1927719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1928719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1929719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*
1930719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1931719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
1932719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1933719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 band;
1934719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 tuner_bands[HPI_TUNER_BAND_LAST];
1935719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 num_bands = 0;
1936719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1937719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1938719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			HPI_TUNER_BAND_LAST);
1939719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1940719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	band = tuner_bands[ucontrol->value.enumerated.item[0]];
1941ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_set_band(h_control, band));
1942719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1943719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 1;
1944719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1945719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1946719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Freq */
1947719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1948719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,
1949719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
1950719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1951719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1952719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
1953719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 tuner_bands[HPI_TUNER_BAND_LAST];
1954719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 num_bands = 0, band_iter, idx;
1955719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 freq_range[3], temp_freq_range[3];
1956719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1957719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1958719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			HPI_TUNER_BAND_LAST);
1959719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1960719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	freq_range[0] = INT_MAX;
1961719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	freq_range[1] = 0;
1962719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	freq_range[2] = INT_MAX;
1963719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1964719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (band_iter = 0; band_iter < num_bands; band_iter++) {
1965719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		for (idx = 0; idx < 3; idx++) {
1966ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			err = hpi_tuner_query_frequency(h_control,
1967719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				idx, tuner_bands[band_iter],
1968719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&temp_freq_range[idx]);
1969719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (err != 0)
1970719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				return err;
1971719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
1972719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1973719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* skip band with bogus stepping */
1974719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (temp_freq_range[2] <= 0)
1975719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			continue;
1976719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1977719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (temp_freq_range[0] < freq_range[0])
1978719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			freq_range[0] = temp_freq_range[0];
1979719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (temp_freq_range[1] > freq_range[1])
1980719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			freq_range[1] = temp_freq_range[1];
1981719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (temp_freq_range[2] < freq_range[2])
1982719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			freq_range[2] = temp_freq_range[2];
1983719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
1984719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1985719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1986719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
1987719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = ((int)freq_range[0]);
1988719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = ((int)freq_range[1]);
1989719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = ((int)freq_range[2]);
1990719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
1991719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
1992719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1993719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,
1994719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
1995719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
1996719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
1997719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 freq;
1998719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
1999ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_get_frequency(h_control, &freq));
2000719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.integer.value[0] = freq;
2001719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2002719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2003719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2004719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2005719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,
2006719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
2007719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2008719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2009719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 freq;
2010719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2011719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	freq = ucontrol->value.integer.value[0];
2012ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_tuner_set_frequency(h_control, freq));
2013719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2014719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 1;
2015719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2016719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2017719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Tuner control group initializer  */
2018719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
2019719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
2020719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2021719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2022719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2023719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2024719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.private_value = hpi_ctl->h_control;
2025719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2026719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2027ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (!hpi_tuner_get_gain(hpi_ctl->h_control, NULL)) {
2028e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		asihpi_ctl_init(&snd_control, hpi_ctl, "Gain");
2029719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.info = snd_asihpi_tuner_gain_info;
2030719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.get = snd_asihpi_tuner_gain_get;
2031719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.put = snd_asihpi_tuner_gain_put;
2032719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2033719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (ctl_add(card, &snd_control, asihpi) < 0)
2034719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -EINVAL;
2035719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2036719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2037e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Band");
2038719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_tuner_band_info;
2039719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_tuner_band_get;
2040719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_tuner_band_put;
2041719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2042719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ctl_add(card, &snd_control, asihpi) < 0)
2043719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
2044719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2045e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Freq");
2046719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_tuner_freq_info;
2047719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_tuner_freq_get;
2048719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_tuner_freq_put;
2049719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2050719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2051719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2052719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2053719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2054719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Meter controls
2055719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2056719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,
2057719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_info *uinfo)
2058719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2059719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2060719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = HPI_MAX_CHANNELS;
2061719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = 0;
2062719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = 0x7FFFFFFF;
2063719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2064719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2065719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2066719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* linear values for 10dB steps */
2067719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int log2lin[] = {
2068719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	0x7FFFFFFF, /* 0dB */
2069719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	679093956,
2070719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	214748365,
2071719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 67909396,
2072719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 21474837,
2073719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	  6790940,
2074719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	  2147484, /* -60dB */
2075719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   679094,
2076719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   214748, /* -80 */
2077719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    67909,
2078719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    21475, /* -100 */
2079719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	     6791,
2080719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	     2147,
2081719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	      679,
2082719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	      214,
2083719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	       68,
2084719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	       21,
2085719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		7,
2086719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		2
2087719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
2088719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2089719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,
2090719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
2091719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2092719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2093719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	short an_gain_mB[HPI_MAX_CHANNELS], i;
2094719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 err;
2095719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2096ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_meter_get_peak(h_control, an_gain_mB);
2097719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2098719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i < HPI_MAX_CHANNELS; i++) {
2099719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err) {
2100719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.integer.value[i] = 0;
2101719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		} else if (an_gain_mB[i] >= 0) {
2102719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.integer.value[i] =
2103719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				an_gain_mB[i] << 16;
2104719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		} else {
2105719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			/* -ve is log value in millibels < -60dB,
2106719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			* convert to (roughly!) linear,
2107719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			*/
2108719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.integer.value[i] =
2109719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					log2lin[an_gain_mB[i] / -1000];
2110719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
2111719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2112719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2113719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2114719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2115719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,
2116719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl, int subidx)
2117719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2118719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2119719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2120719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2121e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Meter");
2122719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access =
2123719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2124719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_meter_info;
2125719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_meter_get;
2126719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2127719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.index = subidx;
2128719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2129719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2130719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2131719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2132719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2133719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Multiplexer controls
2134719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2135719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)
2136719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2137719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = snd_control->private_value;
2138719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_control hpi_ctl;
2139719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int s, err;
2140719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (s = 0; s < 32; s++) {
2141ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_multiplexer_query_source(h_control, s,
2142719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						  &hpi_ctl.
2143719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						  src_node_type,
2144719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						  &hpi_ctl.
2145719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						  src_node_index);
2146719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err)
2147719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2148719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2149719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return s;
2150719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2151719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2152719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
2153719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			       struct snd_ctl_elem_info *uinfo)
2154719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2155719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2156719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 src_node_type, src_node_index;
2157719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2158719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2159719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2160719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2161719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.enumerated.items =
2162719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    snd_card_asihpi_mux_count_sources(kcontrol);
2163719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2164719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2165719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		uinfo->value.enumerated.item =
2166719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    uinfo->value.enumerated.items - 1;
2167719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2168719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err =
2169ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_multiplexer_query_source(h_control,
2170719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					uinfo->value.enumerated.item,
2171719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					&src_node_type, &src_node_index);
2172719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2173719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	sprintf(uinfo->value.enumerated.name, "%s %d",
2174168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],
2175719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		src_node_index);
2176719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2177719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2178719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2179719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
2180719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      struct snd_ctl_elem_value *ucontrol)
2181719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2182719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2183719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source_type, source_index;
2184719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 src_node_type, src_node_index;
2185719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int s;
2186719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2187ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_multiplexer_get_source(h_control,
2188719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&source_type, &source_index));
2189719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* Should cache this search result! */
2190719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (s = 0; s < 256; s++) {
2191ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (hpi_multiplexer_query_source(h_control, s,
2192719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					    &src_node_type, &src_node_index))
2193719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2194719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2195719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if ((source_type == src_node_type)
2196719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    && (source_index == src_node_index)) {
2197719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			ucontrol->value.enumerated.item[0] = s;
2198719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return 0;
2199719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
2200719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2201719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printd(KERN_WARNING
2202e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"Control %x failed to match mux source %hu %hu\n",
2203719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		h_control, source_type, source_index);
2204719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = 0;
2205719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2206719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2207719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2208719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,
2209719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      struct snd_ctl_elem_value *ucontrol)
2210719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2211719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
2212719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2213719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source_type, source_index;
2214719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 e;
2215719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2216719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
2217719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2218ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	e = hpi_multiplexer_query_source(h_control,
2219719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    ucontrol->value.enumerated.item[0],
2220719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    &source_type, &source_index);
2221719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!e)
2222719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_handle_error(
2223ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			hpi_multiplexer_set_source(h_control,
2224719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						source_type, source_index));
2225719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
2226719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2227719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2228719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2229719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int  __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
2230719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
2231719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2232719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2233719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2234719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2235e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Route");
2236719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2237719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_mux_info;
2238719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_mux_get;
2239719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_mux_put;
2240719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2241719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2242719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2243719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2244719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2245719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2246719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Channel mode controls
2247719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2248719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
2249719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_info *uinfo)
2250719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2251e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	static const char * const mode_names[HPI_CHANNEL_MODE_LAST + 1] = {
2252e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"invalid",
2253e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"Normal", "Swap",
2254e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"From Left", "From Right",
2255e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		"To Left", "To Right"
2256719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	};
2257719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2258719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2259719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 mode;
2260719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int i;
2261e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	u16 mode_map[6];
2262e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	int valid_modes = 0;
2263719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2264719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* HPI channel mode values can be from 1 to 6
2265719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	Some adapters only support a contiguous subset
2266719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	*/
2267719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
2268e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		if (!hpi_channel_mode_query_mode(
2269ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			h_control, i, &mode)) {
2270e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			mode_map[valid_modes] = mode;
2271e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			valid_modes++;
2272e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			}
2273719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2274719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2275719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2276e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	uinfo->value.enumerated.items = valid_modes;
2277719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2278e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	if (uinfo->value.enumerated.item >= valid_modes)
2279e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		uinfo->value.enumerated.item = valid_modes - 1;
2280719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2281719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	strcpy(uinfo->value.enumerated.name,
2282e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	       mode_names[mode_map[uinfo->value.enumerated.item]]);
2283719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2284719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2285719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2286719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2287719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
2288719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
2289719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2290719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2291719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 mode;
2292719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2293ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (hpi_channel_mode_get(h_control, &mode))
2294719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		mode = 1;
2295719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2296719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = mode - 1;
2297719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2298719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2299719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2300719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2301719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,
2302719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				struct snd_ctl_elem_value *ucontrol)
2303719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2304719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
2305719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2306719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2307719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
2308719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2309ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_channel_mode_set(h_control,
2310719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			   ucontrol->value.enumerated.item[0] + 1));
2311719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
2312719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2313719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2314719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2315719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
2316719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
2317719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2318719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2319719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2320719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2321e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Mode");
2322719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2323719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_cmode_info;
2324719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_cmode_get;
2325719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_cmode_put;
2326719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2327719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2328719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2329719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2330719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2331719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Sampleclock source  controls
2332719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2333ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassettstatic char *sampleclock_sources[MAX_CLOCKSOURCES] = {
2334ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
2335ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"SMPTE", "Digital1", "Auto", "Network", "Invalid",
2336ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"Prev Module",
2337ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"Digital2", "Digital3", "Digital4", "Digital5",
2338ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	"Digital6", "Digital7", "Digital8"};
2339719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2340719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
2341719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_info *uinfo)
2342719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2343719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi =
2344719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(struct snd_card_asihpi *)(kcontrol->private_data);
2345719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache *clkcache = &asihpi->cc;
2346719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2347719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2348719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.enumerated.items = clkcache->count;
2349719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2350719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2351719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		uinfo->value.enumerated.item =
2352719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				uinfo->value.enumerated.items - 1;
2353719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2354719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	strcpy(uinfo->value.enumerated.name,
2355719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	       clkcache->s[uinfo->value.enumerated.item].name);
2356719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2357719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2358719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2359719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
2360719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
2361719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2362719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi =
2363719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(struct snd_card_asihpi *)(kcontrol->private_data);
2364719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache *clkcache = &asihpi->cc;
2365719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2366719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source, srcindex = 0;
2367719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int i;
2368719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2369719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = 0;
2370ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	if (hpi_sample_clock_get_source(h_control, &source))
2371719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		source = 0;
2372719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2373719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2374ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if (hpi_sample_clock_get_source_index(h_control, &srcindex))
2375719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			srcindex = 0;
2376719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2377719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i < clkcache->count; i++)
2378719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if ((clkcache->s[i].source == source) &&
2379719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(clkcache->s[i].index == srcindex))
2380719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2381719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2382719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	ucontrol->value.enumerated.item[0] = i;
2383719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2384719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2385719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2386719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2387719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
2388719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 struct snd_ctl_elem_value *ucontrol)
2389719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2390719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi =
2391719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			(struct snd_card_asihpi *)(kcontrol->private_data);
2392719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache *clkcache = &asihpi->cc;
2393719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change, item;
2394719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2395719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2396719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
2397719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	item = ucontrol->value.enumerated.item[0];
2398719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (item >= clkcache->count)
2399719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		item = clkcache->count-1;
2400719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2401ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_sample_clock_set_source(
2402719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				h_control, clkcache->s[item].source));
2403719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2404719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2405ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		hpi_handle_error(hpi_sample_clock_set_source_index(
2406719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				h_control, clkcache->s[item].index));
2407719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
2408719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2409719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2410719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2411719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Clkrate controls
2412719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2413719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* Need to change this to enumerated control with list of rates */
2414719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol,
2415719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				   struct snd_ctl_elem_info *uinfo)
2416719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2417719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2418719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2419719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = 8000;
2420719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = 192000;
2421719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = 100;
2422719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2423719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2424719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2425719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2426719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,
2427719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_value *ucontrol)
2428719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2429719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2430719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 rate;
2431719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 e;
2432719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2433ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	e = hpi_sample_clock_get_local_rate(h_control, &rate);
2434719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!e)
2435719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.integer.value[0] = rate;
2436719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2437719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.integer.value[0] = 0;
2438719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2439719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2440719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2441719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,
2442719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_value *ucontrol)
2443719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2444719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int change;
2445719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2446719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2447719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/*  change = asihpi->mixer_clkrate[addr][0] != left ||
2448719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	   asihpi->mixer_clkrate[addr][1] != right;
2449719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	 */
2450719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	change = 1;
2451ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_sample_clock_set_local_rate(h_control,
2452719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				      ucontrol->value.integer.value[0]));
2453719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return change;
2454719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2455719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2456719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol,
2457719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				   struct snd_ctl_elem_info *uinfo)
2458719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2459719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2460719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->count = 1;
2461719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.min = 8000;
2462719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.max = 192000;
2463719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	uinfo->value.integer.step = 100;
2464719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2465719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2466719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2467719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2468719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
2469719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  struct snd_ctl_elem_value *ucontrol)
2470719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2471719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control = kcontrol->private_value;
2472719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 rate;
2473719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 e;
2474719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2475ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	e = hpi_sample_clock_get_sample_rate(h_control, &rate);
2476719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!e)
2477719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.integer.value[0] = rate;
2478719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2479719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		ucontrol->value.integer.value[0] = 0;
2480719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2481719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2482719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2483719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
2484719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					struct hpi_control *hpi_ctl)
2485719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2486719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2487719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_kcontrol_new snd_control;
2488719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2489719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct clk_cache *clkcache = &asihpi->cc;
2490719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 hSC =  hpi_ctl->h_control;
2491719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int has_aes_in = 0;
2492719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int i, j;
2493719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source;
2494719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2495719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.private_value = hpi_ctl->h_control;
2496719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2497719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	clkcache->has_local = 0;
2498719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2499719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {
2500ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		if  (hpi_sample_clock_query_source(hSC,
2501719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				i, &source))
2502719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2503719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		clkcache->s[i].source = source;
2504719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		clkcache->s[i].index = 0;
2505719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		clkcache->s[i].name = sampleclock_sources[source];
2506719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2507719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			has_aes_in = 1;
2508719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL)
2509719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			clkcache->has_local = 1;
2510719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2511719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (has_aes_in)
2512719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* already will have picked up index 0 above */
2513719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		for (j = 1; j < 8; j++) {
2514ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			if (hpi_sample_clock_query_source_index(hSC,
2515719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,
2516719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&source))
2517719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
2518719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			clkcache->s[i].source =
2519719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT;
2520719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			clkcache->s[i].index = j;
2521719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			clkcache->s[i].name = sampleclock_sources[
2522719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					j+HPI_SAMPLECLOCK_SOURCE_LAST];
2523719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			i++;
2524719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
2525719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	clkcache->count = i;
2526719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2527e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Source");
2528719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2529719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_clksrc_info;
2530719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_clksrc_get;
2531719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.put = snd_asihpi_clksrc_put;
2532719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (ctl_add(card, &snd_control, asihpi) < 0)
2533719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
2534719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2535719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2536719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (clkcache->has_local) {
2537e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett		asihpi_ctl_init(&snd_control, hpi_ctl, "Localrate");
2538719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2539719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.info = snd_asihpi_clklocal_info;
2540719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.get = snd_asihpi_clklocal_get;
2541719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_control.put = snd_asihpi_clklocal_put;
2542719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2543719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2544719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (ctl_add(card, &snd_control, asihpi) < 0)
2545719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return -EINVAL;
2546719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2547719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2548e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	asihpi_ctl_init(&snd_control, hpi_ctl, "Rate");
2549719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.access =
2550719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2551719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.info = snd_asihpi_clkrate_info;
2552719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_control.get = snd_asihpi_clkrate_get;
2553719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2554719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return ctl_add(card, &snd_control, asihpi);
2555719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2556719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2557719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   Mixer
2558719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2559719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2560719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
2561719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2562719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card = asihpi->card;
2563719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int idx = 0;
2564719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	unsigned int subindex = 0;
2565719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2566719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_control hpi_ctl, prev_ctl;
2567719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2568719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (snd_BUG_ON(!asihpi))
2569719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -EINVAL;
2570e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett	strcpy(card->mixername, "Asihpi Mixer");
2571719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2572719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err =
2573ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	    hpi_mixer_open(asihpi->adapter_index,
2574719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			  &asihpi->h_mixer);
2575719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_handle_error(err);
2576719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
2577719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -err;
2578719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
257921896bc010c17e5ac58951e771496ec2fb1051edTakashi Iwai	memset(&prev_ctl, 0, sizeof(prev_ctl));
258021896bc010c17e5ac58951e771496ec2fb1051edTakashi Iwai	prev_ctl.control_type = -1;
258121896bc010c17e5ac58951e771496ec2fb1051edTakashi Iwai
2582719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	for (idx = 0; idx < 2000; idx++) {
2583719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = hpi_mixer_get_control_by_index(
2584ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett				asihpi->h_mixer,
2585719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				idx,
2586719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.src_node_type,
2587719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.src_node_index,
2588719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.dst_node_type,
2589719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.dst_node_index,
2590719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.control_type,
2591719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				&hpi_ctl.h_control);
2592719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err) {
2593719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (err == HPI_ERROR_CONTROL_DISABLED) {
2594719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				if (mixer_dump)
2595719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					snd_printk(KERN_INFO
2596e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett						   "Disabled HPI Control(%d)\n",
2597719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						   idx);
2598719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				continue;
2599719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			} else
2600719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				break;
2601719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2602719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		}
2603719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2604168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;
2605168f1b07ccc0e8edecb67fab2d0670861853e2fdEliot Blennerhassett		hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;
2606719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2607719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* ASI50xx in SSX mode has multiple meters on the same node.
2608719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   Use subindex to create distinct ALSA controls
2609719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		   for any duplicated controls.
2610719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		*/
2611719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if ((hpi_ctl.control_type == prev_ctl.control_type) &&
2612719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    (hpi_ctl.src_node_type == prev_ctl.src_node_type) &&
2613719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    (hpi_ctl.src_node_index == prev_ctl.src_node_index) &&
2614719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) &&
2615719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    (hpi_ctl.dst_node_index == prev_ctl.dst_node_index))
2616719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			subindex++;
2617719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		else
2618719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			subindex = 0;
2619719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2620719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		prev_ctl = hpi_ctl;
2621719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2622719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		switch (hpi_ctl.control_type) {
2623719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_VOLUME:
2624719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_volume_add(asihpi, &hpi_ctl);
2625719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2626719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_LEVEL:
2627719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_level_add(asihpi, &hpi_ctl);
2628719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2629719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_MULTIPLEXER:
2630719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_mux_add(asihpi, &hpi_ctl);
2631719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2632719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_CHANNEL_MODE:
2633719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_cmode_add(asihpi, &hpi_ctl);
2634719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2635719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_METER:
2636719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex);
2637719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2638719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_SAMPLECLOCK:
2639719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_sampleclock_add(
2640719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett						asihpi, &hpi_ctl);
2641719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2642719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_CONNECTION:	/* ignore these */
2643719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			continue;
2644719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_TUNER:
2645719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_tuner_add(asihpi, &hpi_ctl);
2646719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2647719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_AESEBU_TRANSMITTER:
2648719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl);
2649719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2650719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_AESEBU_RECEIVER:
2651719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl);
2652719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			break;
2653719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_VOX:
2654719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_BITSTREAM:
2655719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_MICROPHONE:
2656719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_PARAMETRIC_EQ:
2657719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		case HPI_CONTROL_COMPANDER:
2658719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		default:
2659719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			if (mixer_dump)
2660719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				snd_printk(KERN_INFO
2661e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett					"Untranslated HPI Control"
2662719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					"(%d) %d %d %d %d %d\n",
2663719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					idx,
2664719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.control_type,
2665719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.src_node_type,
2666719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.src_node_index,
2667719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.dst_node_type,
2668719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					hpi_ctl.dst_node_index);
2669719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			continue;
2670719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		};
2671719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err < 0)
2672719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return err;
2673719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2674719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (HPI_ERROR_INVALID_OBJ_INDEX != err)
2675719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_handle_error(err);
2676719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2677719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printk(KERN_INFO "%d mixer controls found\n", idx);
2678719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2679719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2680719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2681719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2682719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2683719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   /proc interface
2684719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2685719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2686719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void
2687719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettsnd_asihpi_proc_read(struct snd_info_entry *entry,
2688719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			struct snd_info_buffer *buffer)
2689719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2690719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi = entry->private_data;
2691719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 version;
2692719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
2693719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 rate = 0;
2694719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 source = 0;
2695719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2696719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2697719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_iprintf(buffer, "ASIHPI driver proc file\n");
2698719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_iprintf(buffer,
2699719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		"adapter ID=%4X\n_index=%d\n"
2700719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		"num_outstreams=%d\n_num_instreams=%d\n",
2701719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->type, asihpi->adapter_index,
2702719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->num_outstreams, asihpi->num_instreams);
2703719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2704719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	version = asihpi->version;
2705719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_iprintf(buffer,
2706719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		"serial#=%d\n_hw version %c%d\nDSP code version %03d\n",
2707719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->serial_number, ((version >> 3) & 0xf) + 'A',
2708719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		version & 0x7,
2709719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		((version >> 13) * 100) + ((version >> 7) & 0x3f));
2710719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2711ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_mixer_get_control(asihpi->h_mixer,
2712719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2713719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_CONTROL_SAMPLECLOCK, &h_control);
2714719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2715719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err) {
2716ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err = hpi_sample_clock_get_sample_rate(
2717719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett					h_control, &rate);
2718ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett		err += hpi_sample_clock_get_source(h_control, &source);
2719719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2720719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (!err)
2721719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n",
2722719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			rate, sampleclock_sources[source]);
2723719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2724719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2725719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2726719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2727719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2728719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
2729719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2730719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_info_entry *entry;
2731719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2732719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!snd_card_proc_new(asihpi->card, "info", &entry))
2733719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_info_set_text_ops(entry, asihpi, snd_asihpi_proc_read);
2734719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2735719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2736719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2737719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   HWDEP
2738719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2739719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2740719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file)
2741719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2742719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (enable_hpi_hwdep)
2743719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return 0;
2744719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2745719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENODEV;
2746719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2747719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2748719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2749719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file)
2750719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2751719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (enable_hpi_hwdep)
2752719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return asihpi_hpi_release(file);
2753719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2754719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENODEV;
2755719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2756719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2757719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
2758719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				unsigned int cmd, unsigned long arg)
2759719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2760719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (enable_hpi_hwdep)
2761719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return asihpi_hpi_ioctl(file, cmd, arg);
2762719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2763719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENODEV;
2764719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2765719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2766719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2767719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/* results in /dev/snd/hwC#D0 file for each card with index #
2768719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
2769719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett*/
2770719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
2771719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int device, struct snd_hwdep **rhwdep)
2772719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2773719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_hwdep *hw;
2774719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2775719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2776719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (rhwdep)
2777719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		*rhwdep = NULL;
2778719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
2779719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
2780719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
2781719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	strcpy(hw->name, "asihpi (HPI)");
2782719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->iface = SNDRV_HWDEP_IFACE_LAST;
2783719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->ops.open = snd_asihpi_hpi_open;
2784719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->ops.ioctl = snd_asihpi_hpi_ioctl;
2785719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->ops.release = snd_asihpi_hpi_release;
2786719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hw->private_data = asihpi;
2787719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (rhwdep)
2788719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		*rhwdep = hw;
2789719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return 0;
2790719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2791719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2792719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*------------------------------------------------------------
2793719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett   CARD
2794719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett ------------------------------------------------------------*/
2795719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
2796719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				       const struct pci_device_id *pci_id)
2797719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2798719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int err;
2799719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2800719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u16 version;
2801719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	int pcm_substreams;
2802719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2803719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_adapter *hpi_card;
2804719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card *card;
2805719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct snd_card_asihpi *asihpi;
2806719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2807719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_control;
2808719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	u32 h_stream;
2809719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2810719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	static int dev;
2811719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (dev >= SNDRV_CARDS)
2812719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENODEV;
2813719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2814719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* Should this be enable[hpi_card->index] ? */
2815719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!enable[dev]) {
2816719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		dev++;
2817719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return -ENOENT;
2818719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2819719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2820719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = asihpi_adapter_probe(pci_dev, pci_id);
2821719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0)
2822719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return err;
2823719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2824719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_card = pci_get_drvdata(pci_dev);
2825719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* first try to give the card the same index as its hardware index */
2826719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_create(hpi_card->index,
2827719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      id[hpi_card->index], THIS_MODULE,
2828719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      sizeof(struct snd_card_asihpi),
2829719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			      &card);
2830719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0) {
2831719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		/* if that fails, try the default index==next available */
2832719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err =
2833719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		    snd_card_create(index[dev], id[dev],
2834719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    THIS_MODULE,
2835719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    sizeof(struct snd_card_asihpi),
2836719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				    &card);
2837719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		if (err < 0)
2838719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			return err;
2839719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_printk(KERN_WARNING
2840e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			"**** WARNING **** Adapter index %d->ALSA index %d\n",
2841719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			hpi_card->index, card->number);
2842719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2843719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
28441225367a481ae751738630158c7ca96aa1c7bac8Eliot Blennerhassett	snd_card_set_dev(card, &pci_dev->dev);
28451225367a481ae751738630158c7ca96aa1c7bac8Eliot Blennerhassett
2846719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi = (struct snd_card_asihpi *) card->private_data;
2847719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi->card = card;
28481225367a481ae751738630158c7ca96aa1c7bac8Eliot Blennerhassett	asihpi->pci = pci_dev;
2849719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi->adapter_index = hpi_card->index;
2850ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_adapter_get_info(
2851719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 asihpi->adapter_index,
2852719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 &asihpi->num_outstreams,
2853719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 &asihpi->num_instreams,
2854719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 &asihpi->version,
2855719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				 &asihpi->serial_number, &asihpi->type));
2856719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2857719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	version = asihpi->version;
2858719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d "
2859719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			"num_instreams=%d S/N=%d\n"
2860e64b1a28c532009edd6a8a7b906c280fc2a4b90aEliot Blennerhassett			"Hw Version %c%d DSP code version %03d\n",
2861719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->type, asihpi->adapter_index,
2862719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->num_outstreams,
2863719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->num_instreams, asihpi->serial_number,
2864719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			((version >> 3) & 0xf) + 'A',
2865719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			version & 0x7,
2866719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			((version >> 13) * 100) + ((version >> 7) & 0x3f));
2867719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2868719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pcm_substreams = asihpi->num_outstreams;
2869719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (pcm_substreams < asihpi->num_instreams)
2870719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		pcm_substreams = asihpi->num_instreams;
2871719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2872ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_adapter_get_property(asihpi->adapter_index,
2873719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_ADAPTER_PROPERTY_CAPS1,
2874719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		NULL, &asihpi->support_grouping);
2875719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
2876719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->support_grouping = 0;
2877719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2878ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_adapter_get_property(asihpi->adapter_index,
2879719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_ADAPTER_PROPERTY_CAPS2,
2880719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		&asihpi->support_mrx, NULL);
2881719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
2882719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->support_mrx = 0;
2883719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2884ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_adapter_get_property(asihpi->adapter_index,
2885719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_ADAPTER_PROPERTY_INTERVAL,
2886719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		NULL, &asihpi->update_interval_frames);
2887719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err)
2888719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->update_interval_frames = 512;
2889719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2890ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
2891719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			     0, &h_stream));
2892719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2893ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_instream_host_buffer_free(h_stream);
2894719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi->support_mmap = (!err);
2895719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2896ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	hpi_handle_error(hpi_instream_close(h_stream));
2897719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2898ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_adapter_get_property(asihpi->adapter_index,
2899719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_ADAPTER_PROPERTY_CURCHANNELS,
2900719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		&asihpi->in_max_chans, &asihpi->out_max_chans);
2901719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err) {
2902719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->in_max_chans = 2;
2903719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		asihpi->out_max_chans = 2;
2904719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2905719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2906719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n",
2907719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->support_mmap,
2908719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->support_grouping,
2909719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			asihpi->support_mrx
2910719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	      );
2911719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2912719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2913719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams);
2914719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0) {
2915719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_printk(KERN_ERR "pcm_new failed\n");
2916719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		goto __nodev;
2917719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2918719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_asihpi_mixer_new(asihpi);
2919719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (err < 0) {
2920719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		snd_printk(KERN_ERR "mixer_new failed\n");
2921719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		goto __nodev;
2922719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2923719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2924ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett	err = hpi_mixer_get_control(asihpi->h_mixer,
2925719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2926719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett				  HPI_CONTROL_SAMPLECLOCK, &h_control);
2927719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2928719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err)
2929719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		err = hpi_sample_clock_set_local_rate(
2930ba94455c29c383713c360537b6323e3bd4c76434Eliot Blennerhassett			h_control, adapter_fs);
2931719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2932719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_asihpi_proc_init(asihpi);
2933719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2934719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	/* always create, can be enabled or disabled dynamically
2935719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	    by enable_hwdep  module param*/
2936719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_asihpi_hpi_new(asihpi, 0, NULL);
2937719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2938719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (asihpi->support_mmap)
2939719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		strcpy(card->driver, "ASIHPI-MMAP");
2940719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	else
2941719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		strcpy(card->driver, "ASIHPI");
2942719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2943719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
2944719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	sprintf(card->longname, "%s %i",
2945719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett			card->shortname, asihpi->adapter_index);
2946719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	err = snd_card_register(card);
2947719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	if (!err) {
2948719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		hpi_card->snd_card_asihpi = card;
2949719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		dev++;
2950719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		return 0;
2951719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	}
2952719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett__nodev:
2953719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_free(card);
2954719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err);
2955719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return err;
2956719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2957719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2958719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2959719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void __devexit snd_asihpi_remove(struct pci_dev *pci_dev)
2960719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2961719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev);
2962719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2963719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	snd_card_free(hpi_card->snd_card_asihpi);
2964719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	hpi_card->snd_card_asihpi = NULL;
2965719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi_adapter_remove(pci_dev);
2966719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2967719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2968719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = {
2969719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	{HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
2970719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2971719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		(kernel_ulong_t)HPI_6205},
2972719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	{HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
2973719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2974719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett		(kernel_ulong_t)HPI_6000},
2975719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	{0,}
2976719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
2977719f82d3987aad4cc9f46d19c35f362672545cadEliot BlennerhassettMODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
2978719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2979719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic struct pci_driver driver = {
2980719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.name = "asihpi",
2981719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.id_table = asihpi_pci_tbl,
2982719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.probe = snd_asihpi_probe,
2983719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.remove = __devexit_p(snd_asihpi_remove),
2984719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#ifdef CONFIG_PM
2985719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett/*	.suspend = snd_asihpi_suspend,
2986719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	.resume = snd_asihpi_resume, */
2987719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett#endif
2988719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett};
2989719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2990719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic int __init snd_asihpi_init(void)
2991719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2992719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi_init();
2993719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	return pci_register_driver(&driver);
2994719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
2995719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2996719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettstatic void __exit snd_asihpi_exit(void)
2997719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett{
2998719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
2999719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	pci_unregister_driver(&driver);
3000719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett	asihpi_exit();
3001719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett}
3002719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
3003719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_init(snd_asihpi_init)
3004719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassettmodule_exit(snd_asihpi_exit)
3005719f82d3987aad4cc9f46d19c35f362672545cadEliot Blennerhassett
3006