aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/mixart
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/pci/mixart
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'sound/pci/mixart')
-rw-r--r--sound/pci/mixart/Makefile8
-rw-r--r--sound/pci/mixart/mixart.c1443
-rw-r--r--sound/pci/mixart/mixart.h242
-rw-r--r--sound/pci/mixart/mixart_core.c588
-rw-r--r--sound/pci/mixart/mixart_core.h607
-rw-r--r--sound/pci/mixart/mixart_hwdep.c647
-rw-r--r--sound/pci/mixart/mixart_hwdep.h145
-rw-r--r--sound/pci/mixart/mixart_mixer.c1136
-rw-r--r--sound/pci/mixart/mixart_mixer.h31
9 files changed, 4847 insertions, 0 deletions
diff --git a/sound/pci/mixart/Makefile b/sound/pci/mixart/Makefile
new file mode 100644
index 000000000000..fe6ba0c4b567
--- /dev/null
+++ b/sound/pci/mixart/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for ALSA
3# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o
7
8obj-$(CONFIG_SND_MIXART) += snd-mixart.o
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
new file mode 100644
index 000000000000..65bb0f47af2c
--- /dev/null
+++ b/sound/pci/mixart/mixart.c
@@ -0,0 +1,1443 @@
1/*
2 * Driver for Digigram miXart soundcards
3 *
4 * main file with alsa callbacks
5 *
6 * Copyright (c) 2003 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23
24#include <sound/driver.h>
25#include <linux/init.h>
26#include <linux/interrupt.h>
27#include <linux/pci.h>
28#include <linux/moduleparam.h>
29#include <sound/core.h>
30#include <sound/initval.h>
31#include <sound/info.h>
32#include <sound/control.h>
33#include <sound/pcm.h>
34#include <sound/pcm_params.h>
35#include "mixart.h"
36#include "mixart_hwdep.h"
37#include "mixart_core.h"
38#include "mixart_mixer.h"
39
40#define CARD_NAME "miXart"
41
42MODULE_AUTHOR("Digigram <alsa@digigram.com>");
43MODULE_DESCRIPTION("Digigram " CARD_NAME);
44MODULE_LICENSE("GPL");
45MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}");
46
47static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
48static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
49static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
50
51module_param_array(index, int, NULL, 0444);
52MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard.");
53module_param_array(id, charp, NULL, 0444);
54MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard.");
55module_param_array(enable, bool, NULL, 0444);
56MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
57
58/*
59 */
60
61static struct pci_device_id snd_mixart_ids[] = {
62 { 0x1057, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* MC8240 */
63 { 0, }
64};
65
66MODULE_DEVICE_TABLE(pci, snd_mixart_ids);
67
68
69static int mixart_set_pipe_state(mixart_mgr_t *mgr, mixart_pipe_t* pipe, int start)
70{
71 mixart_group_state_req_t group_state;
72 mixart_group_state_resp_t group_state_resp;
73 mixart_msg_t request;
74 int err;
75 u32 system_msg_uid;
76
77 switch(pipe->status) {
78 case PIPE_RUNNING:
79 case PIPE_CLOCK_SET:
80 if(start) return 0; /* already started */
81 break;
82 case PIPE_STOPPED:
83 if(!start) return 0; /* already stopped */
84 break;
85 default:
86 snd_printk(KERN_ERR "error mixart_set_pipe_state called with wrong pipe->status!\n");
87 return -EINVAL; /* function called with wrong pipe status */
88 }
89
90 system_msg_uid = 0x12345678; /* the event ! (take care: the MSB and two LSB's have to be 0) */
91
92 /* wait on the last MSG_SYSTEM_SEND_SYNCHRO_CMD command to be really finished */
93
94 request.message_id = MSG_SYSTEM_WAIT_SYNCHRO_CMD;
95 request.uid = (mixart_uid_t){0,0};
96 request.data = &system_msg_uid;
97 request.size = sizeof(system_msg_uid);
98
99 err = snd_mixart_send_msg_wait_notif(mgr, &request, system_msg_uid);
100 if(err) {
101 snd_printk(KERN_ERR "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n");
102 return err;
103 }
104
105 /* start or stop the pipe (1 pipe) */
106
107 memset(&group_state, 0, sizeof(group_state));
108 group_state.pipe_count = 1;
109 group_state.pipe_uid[0] = pipe->group_uid;
110
111 if(start)
112 request.message_id = MSG_STREAM_START_STREAM_GRP_PACKET;
113 else
114 request.message_id = MSG_STREAM_STOP_STREAM_GRP_PACKET;
115
116 request.uid = pipe->group_uid; /*(mixart_uid_t){0,0};*/
117 request.data = &group_state;
118 request.size = sizeof(group_state);
119
120 err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
121 if (err < 0 || group_state_resp.txx_status != 0) {
122 snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
123 return -EINVAL;
124 }
125
126 if(start) {
127 u32 stat;
128
129 group_state.pipe_count = 0; /* in case of start same command once again with pipe_count=0 */
130
131 err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
132 if (err < 0 || group_state_resp.txx_status != 0) {
133 snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
134 return -EINVAL;
135 }
136
137 /* in case of start send a synchro top */
138
139 request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
140 request.uid = (mixart_uid_t){0,0};
141 request.data = NULL;
142 request.size = 0;
143
144 err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat);
145 if (err < 0 || stat != 0) {
146 snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", err, stat);
147 return -EINVAL;
148 }
149
150 pipe->status = PIPE_RUNNING;
151 }
152 else /* !start */
153 pipe->status = PIPE_STOPPED;
154
155 return 0;
156}
157
158
159static int mixart_set_clock(mixart_mgr_t *mgr, mixart_pipe_t *pipe, unsigned int rate)
160{
161 mixart_msg_t request;
162 mixart_clock_properties_t clock_properties;
163 mixart_clock_properties_resp_t clock_prop_resp;
164 int err;
165
166 switch(pipe->status) {
167 case PIPE_CLOCK_SET:
168 break;
169 case PIPE_RUNNING:
170 if(rate != 0)
171 break;
172 default:
173 if(rate == 0)
174 return 0; /* nothing to do */
175 else {
176 snd_printk(KERN_ERR "error mixart_set_clock(%d) called with wrong pipe->status !\n", rate);
177 return -EINVAL;
178 }
179 }
180
181 memset(&clock_properties, 0, sizeof(clock_properties));
182 clock_properties.clock_generic_type = (rate != 0) ? CGT_INTERNAL_CLOCK : CGT_NO_CLOCK;
183 clock_properties.clock_mode = CM_STANDALONE;
184 clock_properties.frequency = rate;
185 clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */
186 clock_properties.uid_caller[0] = pipe->group_uid;
187
188 snd_printdd("mixart_set_clock to %d kHz\n", rate);
189
190 request.message_id = MSG_CLOCK_SET_PROPERTIES;
191 request.uid = mgr->uid_console_manager;
192 request.data = &clock_properties;
193 request.size = sizeof(clock_properties);
194
195 err = snd_mixart_send_msg(mgr, &request, sizeof(clock_prop_resp), &clock_prop_resp);
196 if (err < 0 || clock_prop_resp.status != 0 || clock_prop_resp.clock_mode != CM_STANDALONE) {
197 snd_printk(KERN_ERR "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", err, clock_prop_resp.status, clock_prop_resp.clock_mode);
198 return -EINVAL;
199 }
200
201 if(rate) pipe->status = PIPE_CLOCK_SET;
202 else pipe->status = PIPE_RUNNING;
203
204 return 0;
205}
206
207
208/*
209 * Allocate or reference output pipe for analog IOs (pcmp0/1)
210 */
211mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring)
212{
213 int stream_count;
214 mixart_pipe_t *pipe;
215 mixart_msg_t request;
216
217 if(capture) {
218 if (pcm_number == MIXART_PCM_ANALOG) {
219 pipe = &(chip->pipe_in_ana); /* analog inputs */
220 } else {
221 pipe = &(chip->pipe_in_dig); /* digital inputs */
222 }
223 request.message_id = MSG_STREAM_ADD_OUTPUT_GROUP;
224 stream_count = MIXART_CAPTURE_STREAMS;
225 } else {
226 if (pcm_number == MIXART_PCM_ANALOG) {
227 pipe = &(chip->pipe_out_ana); /* analog outputs */
228 } else {
229 pipe = &(chip->pipe_out_dig); /* digital outputs */
230 }
231 request.message_id = MSG_STREAM_ADD_INPUT_GROUP;
232 stream_count = MIXART_PLAYBACK_STREAMS;
233 }
234
235 /* a new stream is opened and there are already all streams in use */
236 if( (monitoring == 0) && (pipe->references >= stream_count) ) {
237 return NULL;
238 }
239
240 /* pipe is not yet defined */
241 if( pipe->status == PIPE_UNDEFINED ) {
242 int err, i;
243 struct {
244 mixart_streaming_group_req_t sgroup_req;
245 mixart_streaming_group_t sgroup_resp;
246 } *buf;
247
248 snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number);
249
250 buf = kmalloc(sizeof(*buf), GFP_KERNEL);
251 if (!buf)
252 return NULL;
253
254 request.uid = (mixart_uid_t){0,0}; /* should be StreamManagerUID, but zero is OK if there is only one ! */
255 request.data = &buf->sgroup_req;
256 request.size = sizeof(buf->sgroup_req);
257
258 memset(&buf->sgroup_req, 0, sizeof(buf->sgroup_req));
259
260 buf->sgroup_req.stream_count = stream_count;
261 buf->sgroup_req.channel_count = 2;
262 buf->sgroup_req.latency = 256;
263 buf->sgroup_req.connector = pipe->uid_left_connector; /* the left connector */
264
265 for (i=0; i<stream_count; i++) {
266 int j;
267 struct mixart_flowinfo *flowinfo;
268 struct mixart_bufferinfo *bufferinfo;
269
270 /* we don't yet know the format, so config 16 bit pcm audio for instance */
271 buf->sgroup_req.stream_info[i].size_max_byte_frame = 1024;
272 buf->sgroup_req.stream_info[i].size_max_sample_frame = 256;
273 buf->sgroup_req.stream_info[i].nb_bytes_max_per_sample = MIXART_FLOAT_P__4_0_TO_HEX; /* is 4.0f */
274
275 /* find the right bufferinfo_array */
276 j = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (pcm_number * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS)) + i;
277 if(capture) j += MIXART_PLAYBACK_STREAMS; /* in the array capture is behind playback */
278
279 buf->sgroup_req.flow_entry[i] = j;
280
281 flowinfo = (struct mixart_flowinfo *)chip->mgr->flowinfo.area;
282 flowinfo[j].bufferinfo_array_phy_address = (u32)chip->mgr->bufferinfo.addr + (j * sizeof(mixart_bufferinfo_t));
283 flowinfo[j].bufferinfo_count = 1; /* 1 will set the miXart to ring-buffer mode ! */
284
285 bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area;
286 bufferinfo[j].buffer_address = 0; /* buffer is not yet allocated */
287 bufferinfo[j].available_length = 0; /* buffer is not yet allocated */
288
289 /* construct the identifier of the stream buffer received in the interrupts ! */
290 bufferinfo[j].buffer_id = (chip->chip_idx << MIXART_NOTIFY_CARD_OFFSET) + (pcm_number << MIXART_NOTIFY_PCM_OFFSET ) + i;
291 if(capture) {
292 bufferinfo[j].buffer_id |= MIXART_NOTIFY_CAPT_MASK;
293 }
294 }
295
296 err = snd_mixart_send_msg(chip->mgr, &request, sizeof(buf->sgroup_resp), &buf->sgroup_resp);
297 if((err < 0) || (buf->sgroup_resp.status != 0)) {
298 snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, buf->sgroup_resp.status);
299 kfree(buf);
300 return NULL;
301 }
302
303 pipe->group_uid = buf->sgroup_resp.group; /* id of the pipe, as returned by embedded */
304 pipe->stream_count = buf->sgroup_resp.stream_count;
305 /* pipe->stream_uid[i] = buf->sgroup_resp.stream[i].stream_uid; */
306
307 pipe->status = PIPE_STOPPED;
308 kfree(buf);
309 }
310
311 if(monitoring) pipe->monitoring = 1;
312 else pipe->references++;
313
314 return pipe;
315}
316
317
318int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring)
319{
320 int err = 0;
321
322 if(pipe->status == PIPE_UNDEFINED)
323 return 0;
324
325 if(monitoring)
326 pipe->monitoring = 0;
327 else
328 pipe->references--;
329
330 if((pipe->references <= 0) && (pipe->monitoring == 0)) {
331
332 mixart_msg_t request;
333 mixart_delete_group_resp_t delete_resp;
334
335 /* release the clock */
336 err = mixart_set_clock( mgr, pipe, 0);
337 if( err < 0 ) {
338 snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n");
339 }
340
341 /* stop the pipe */
342 err = mixart_set_pipe_state(mgr, pipe, 0);
343 if( err < 0 ) {
344 snd_printk(KERN_ERR "error stopping pipe!\n");
345 }
346
347 request.message_id = MSG_STREAM_DELETE_GROUP;
348 request.uid = (mixart_uid_t){0,0};
349 request.data = &pipe->group_uid; /* the streaming group ! */
350 request.size = sizeof(pipe->group_uid);
351
352 /* delete the pipe */
353 err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp);
354 if ((err < 0) || (delete_resp.status != 0)) {
355 snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status);
356 }
357
358 pipe->group_uid = (mixart_uid_t){0,0};
359 pipe->stream_count = 0;
360 pipe->status = PIPE_UNDEFINED;
361 }
362
363 return err;
364}
365
366static int mixart_set_stream_state(mixart_stream_t *stream, int start)
367{
368 mixart_t *chip;
369 mixart_stream_state_req_t stream_state_req;
370 mixart_msg_t request;
371
372 if(!stream->substream)
373 return -EINVAL;
374
375 memset(&stream_state_req, 0, sizeof(stream_state_req));
376 stream_state_req.stream_count = 1;
377 stream_state_req.stream_info.stream_desc.uid_pipe = stream->pipe->group_uid;
378 stream_state_req.stream_info.stream_desc.stream_idx = stream->substream->number;
379
380 if (stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
381 request.message_id = start ? MSG_STREAM_START_INPUT_STAGE_PACKET : MSG_STREAM_STOP_INPUT_STAGE_PACKET;
382 else
383 request.message_id = start ? MSG_STREAM_START_OUTPUT_STAGE_PACKET : MSG_STREAM_STOP_OUTPUT_STAGE_PACKET;
384
385 request.uid = (mixart_uid_t){0,0};
386 request.data = &stream_state_req;
387 request.size = sizeof(stream_state_req);
388
389 stream->abs_period_elapsed = 0; /* reset stream pos */
390 stream->buf_periods = 0;
391 stream->buf_period_frag = 0;
392
393 chip = snd_pcm_substream_chip(stream->substream);
394
395 return snd_mixart_send_msg_nonblock(chip->mgr, &request);
396}
397
398/*
399 * Trigger callback
400 */
401
402static int snd_mixart_trigger(snd_pcm_substream_t *subs, int cmd)
403{
404 mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
405
406 switch (cmd) {
407 case SNDRV_PCM_TRIGGER_START:
408
409 snd_printdd("SNDRV_PCM_TRIGGER_START\n");
410
411 /* START_STREAM */
412 if( mixart_set_stream_state(stream, 1) )
413 return -EINVAL;
414
415 stream->status = MIXART_STREAM_STATUS_RUNNING;
416
417 break;
418 case SNDRV_PCM_TRIGGER_STOP:
419
420 /* STOP_STREAM */
421 if( mixart_set_stream_state(stream, 0) )
422 return -EINVAL;
423
424 stream->status = MIXART_STREAM_STATUS_OPEN;
425
426 snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");
427
428 break;
429
430 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
431 /* TODO */
432 stream->status = MIXART_STREAM_STATUS_PAUSE;
433 snd_printdd("SNDRV_PCM_PAUSE_PUSH\n");
434 break;
435 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
436 /* TODO */
437 stream->status = MIXART_STREAM_STATUS_RUNNING;
438 snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n");
439 break;
440 default:
441 return -EINVAL;
442 }
443 return 0;
444}
445
446static int mixart_sync_nonblock_events(mixart_mgr_t *mgr)
447{
448 int timeout = HZ;
449 while (atomic_read(&mgr->msg_processed) > 0) {
450 if (! timeout--) {
451 snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
452 return -EBUSY;
453 }
454 set_current_state(TASK_UNINTERRUPTIBLE);
455 schedule_timeout(1);
456 }
457 return 0;
458}
459
460/*
461 * prepare callback for all pcms
462 */
463static int snd_mixart_prepare(snd_pcm_substream_t *subs)
464{
465 mixart_t *chip = snd_pcm_substream_chip(subs);
466 mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
467
468 /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
469
470 snd_printdd("snd_mixart_prepare\n");
471
472 mixart_sync_nonblock_events(chip->mgr);
473
474 /* only the first stream can choose the sample rate */
475 /* the further opened streams will be limited to its frequency (see open) */
476 if(chip->mgr->ref_count_rate == 1)
477 chip->mgr->sample_rate = subs->runtime->rate;
478
479 /* set the clock only once (first stream) on the same pipe */
480 if(stream->pipe->references == 1) {
481 if( mixart_set_clock(chip->mgr, stream->pipe, subs->runtime->rate) )
482 return -EINVAL;
483 }
484
485 return 0;
486}
487
488
489static int mixart_set_format(mixart_stream_t *stream, snd_pcm_format_t format)
490{
491 int err;
492 mixart_t *chip;
493 mixart_msg_t request;
494 mixart_stream_param_desc_t stream_param;
495 mixart_return_uid_t resp;
496
497 chip = snd_pcm_substream_chip(stream->substream);
498
499 memset(&stream_param, 0, sizeof(stream_param));
500
501 stream_param.coding_type = CT_LINEAR;
502 stream_param.number_of_channel = stream->channels;
503
504 stream_param.sampling_freq = chip->mgr->sample_rate;
505 if(stream_param.sampling_freq == 0)
506 stream_param.sampling_freq = 44100; /* if frequency not yet defined, use some default */
507
508 switch(format){
509 case SNDRV_PCM_FORMAT_U8:
510 stream_param.sample_type = ST_INTEGER_8;
511 stream_param.sample_size = 8;
512 break;
513 case SNDRV_PCM_FORMAT_S16_LE:
514 stream_param.sample_type = ST_INTEGER_16LE;
515 stream_param.sample_size = 16;
516 break;
517 case SNDRV_PCM_FORMAT_S16_BE:
518 stream_param.sample_type = ST_INTEGER_16BE;
519 stream_param.sample_size = 16;
520 break;
521 case SNDRV_PCM_FORMAT_S24_3LE:
522 stream_param.sample_type = ST_INTEGER_24LE;
523 stream_param.sample_size = 24;
524 break;
525 case SNDRV_PCM_FORMAT_S24_3BE:
526 stream_param.sample_type = ST_INTEGER_24BE;
527 stream_param.sample_size = 24;
528 break;
529 case SNDRV_PCM_FORMAT_FLOAT_LE:
530 stream_param.sample_type = ST_FLOATING_POINT_32LE;
531 stream_param.sample_size = 32;
532 break;
533 case SNDRV_PCM_FORMAT_FLOAT_BE:
534 stream_param.sample_type = ST_FLOATING_POINT_32BE;
535 stream_param.sample_size = 32;
536 break;
537 default:
538 snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n");
539 return -EINVAL;
540 }
541
542 snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
543 stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels);
544
545 /* TODO: what else to configure ? */
546 /* stream_param.samples_per_frame = 2; */
547 /* stream_param.bytes_per_frame = 4; */
548 /* stream_param.bytes_per_sample = 2; */
549
550 stream_param.pipe_count = 1; /* set to 1 */
551 stream_param.stream_count = 1; /* set to 1 */
552 stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid;
553 stream_param.stream_desc[0].stream_idx = stream->substream->number;
554
555 request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM;
556 request.uid = (mixart_uid_t){0,0};
557 request.data = &stream_param;
558 request.size = sizeof(stream_param);
559
560 err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
561 if((err < 0) || resp.error_code) {
562 snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code);
563 return -EINVAL;
564 }
565 return 0;
566}
567
568
569/*
570 * HW_PARAMS callback for all pcms
571 */
572static int snd_mixart_hw_params(snd_pcm_substream_t *subs,
573 snd_pcm_hw_params_t *hw)
574{
575 mixart_t *chip = snd_pcm_substream_chip(subs);
576 mixart_mgr_t *mgr = chip->mgr;
577 mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
578 snd_pcm_format_t format;
579 int err;
580 int channels;
581
582 /* set up channels */
583 channels = params_channels(hw);
584
585 /* set up format for the stream */
586 format = params_format(hw);
587
588 down(&mgr->setup_mutex);
589
590 /* update the stream levels */
591 if( stream->pcm_number <= MIXART_PCM_DIGITAL ) {
592 int is_aes = stream->pcm_number > MIXART_PCM_ANALOG;
593 if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK )
594 mixart_update_playback_stream_level(chip, is_aes, subs->number);
595 else
596 mixart_update_capture_stream_level( chip, is_aes);
597 }
598
599 stream->channels = channels;
600
601 /* set the format to the board */
602 err = mixart_set_format(stream, format);
603 if(err < 0) {
604 return err;
605 }
606
607 /* allocate buffer */
608 err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));
609
610 if (err > 0) {
611 struct mixart_bufferinfo *bufferinfo;
612 int i = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (stream->pcm_number * (MIXART_PLAYBACK_STREAMS+MIXART_CAPTURE_STREAMS)) + subs->number;
613 if( subs->stream == SNDRV_PCM_STREAM_CAPTURE ) {
614 i += MIXART_PLAYBACK_STREAMS; /* in array capture is behind playback */
615 }
616
617 bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area;
618 bufferinfo[i].buffer_address = subs->runtime->dma_addr;
619 bufferinfo[i].available_length = subs->runtime->dma_bytes;
620 /* bufferinfo[i].buffer_id is already defined */
621
622 snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i,
623 bufferinfo[i].buffer_address,
624 bufferinfo[i].available_length,
625 subs->number);
626 }
627 up(&mgr->setup_mutex);
628
629 return err;
630}
631
632static int snd_mixart_hw_free(snd_pcm_substream_t *subs)
633{
634 mixart_t *chip = snd_pcm_substream_chip(subs);
635 snd_pcm_lib_free_pages(subs);
636 mixart_sync_nonblock_events(chip->mgr);
637 return 0;
638}
639
640
641
642/*
643 * TODO CONFIGURATION SPACE for all pcms, mono pcm must update channels_max
644 */
645static snd_pcm_hardware_t snd_mixart_analog_caps =
646{
647 .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
648 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
649 SNDRV_PCM_INFO_PAUSE),
650 .formats = ( SNDRV_PCM_FMTBIT_U8 |
651 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
652 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
653 SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
654 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
655 .rate_min = 8000,
656 .rate_max = 48000,
657 .channels_min = 1,
658 .channels_max = 2,
659 .buffer_bytes_max = (32*1024),
660 .period_bytes_min = 256, /* 256 frames U8 mono*/
661 .period_bytes_max = (16*1024),
662 .periods_min = 2,
663 .periods_max = (32*1024/256),
664};
665
666static snd_pcm_hardware_t snd_mixart_digital_caps =
667{
668 .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
669 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
670 SNDRV_PCM_INFO_PAUSE),
671 .formats = ( SNDRV_PCM_FMTBIT_U8 |
672 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
673 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
674 SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
675 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
676 .rate_min = 32000,
677 .rate_max = 48000,
678 .channels_min = 1,
679 .channels_max = 2,
680 .buffer_bytes_max = (32*1024),
681 .period_bytes_min = 256, /* 256 frames U8 mono*/
682 .period_bytes_max = (16*1024),
683 .periods_min = 2,
684 .periods_max = (32*1024/256),
685};
686
687
688static int snd_mixart_playback_open(snd_pcm_substream_t *subs)
689{
690 mixart_t *chip = snd_pcm_substream_chip(subs);
691 mixart_mgr_t *mgr = chip->mgr;
692 snd_pcm_runtime_t *runtime = subs->runtime;
693 snd_pcm_t *pcm = subs->pcm;
694 mixart_stream_t *stream;
695 mixart_pipe_t *pipe;
696 int err = 0;
697 int pcm_number;
698
699 down(&mgr->setup_mutex);
700
701 if ( pcm == chip->pcm ) {
702 pcm_number = MIXART_PCM_ANALOG;
703 runtime->hw = snd_mixart_analog_caps;
704 } else {
705 snd_assert ( pcm == chip->pcm_dig );
706 pcm_number = MIXART_PCM_DIGITAL;
707 runtime->hw = snd_mixart_digital_caps;
708 }
709 snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
710
711 /* get stream info */
712 stream = &(chip->playback_stream[pcm_number][subs->number]);
713
714 if (stream->status != MIXART_STREAM_STATUS_FREE){
715 /* streams in use */
716 snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
717 err = -EBUSY;
718 goto _exit_open;
719 }
720
721 /* get pipe pointer (out pipe) */
722 pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0);
723
724 if (pipe == NULL) {
725 err = -EINVAL;
726 goto _exit_open;
727 }
728
729 /* start the pipe if necessary */
730 err = mixart_set_pipe_state(chip->mgr, pipe, 1);
731 if( err < 0 ) {
732 snd_printk(KERN_ERR "error starting pipe!\n");
733 snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
734 err = -EINVAL;
735 goto _exit_open;
736 }
737
738 stream->pipe = pipe;
739 stream->pcm_number = pcm_number;
740 stream->status = MIXART_STREAM_STATUS_OPEN;
741 stream->substream = subs;
742 stream->channels = 0; /* not configured yet */
743
744 runtime->private_data = stream;
745
746 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
747 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);
748
749 /* if a sample rate is already used, another stream cannot change */
750 if(mgr->ref_count_rate++) {
751 if(mgr->sample_rate) {
752 runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
753 }
754 }
755
756 _exit_open:
757 up(&mgr->setup_mutex);
758
759 return err;
760}
761
762
763static int snd_mixart_capture_open(snd_pcm_substream_t *subs)
764{
765 mixart_t *chip = snd_pcm_substream_chip(subs);
766 mixart_mgr_t *mgr = chip->mgr;
767 snd_pcm_runtime_t *runtime = subs->runtime;
768 snd_pcm_t *pcm = subs->pcm;
769 mixart_stream_t *stream;
770 mixart_pipe_t *pipe;
771 int err = 0;
772 int pcm_number;
773
774 down(&mgr->setup_mutex);
775
776 if ( pcm == chip->pcm ) {
777 pcm_number = MIXART_PCM_ANALOG;
778 runtime->hw = snd_mixart_analog_caps;
779 } else {
780 snd_assert ( pcm == chip->pcm_dig );
781 pcm_number = MIXART_PCM_DIGITAL;
782 runtime->hw = snd_mixart_digital_caps;
783 }
784
785 runtime->hw.channels_min = 2; /* for instance, no mono */
786
787 snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
788
789 /* get stream info */
790 stream = &(chip->capture_stream[pcm_number]);
791
792 if (stream->status != MIXART_STREAM_STATUS_FREE){
793 /* streams in use */
794 snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
795 err = -EBUSY;
796 goto _exit_open;
797 }
798
799 /* get pipe pointer (in pipe) */
800 pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0);
801
802 if (pipe == NULL) {
803 err = -EINVAL;
804 goto _exit_open;
805 }
806
807 /* start the pipe if necessary */
808 err = mixart_set_pipe_state(chip->mgr, pipe, 1);
809 if( err < 0 ) {
810 snd_printk(KERN_ERR "error starting pipe!\n");
811 snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
812 err = -EINVAL;
813 goto _exit_open;
814 }
815
816 stream->pipe = pipe;
817 stream->pcm_number = pcm_number;
818 stream->status = MIXART_STREAM_STATUS_OPEN;
819 stream->substream = subs;
820 stream->channels = 0; /* not configured yet */
821
822 runtime->private_data = stream;
823
824 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
825 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);
826
827 /* if a sample rate is already used, another stream cannot change */
828 if(mgr->ref_count_rate++) {
829 if(mgr->sample_rate) {
830 runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
831 }
832 }
833
834 _exit_open:
835 up(&mgr->setup_mutex);
836
837 return err;
838}
839
840
841
842static int snd_mixart_close(snd_pcm_substream_t *subs)
843{
844 mixart_t *chip = snd_pcm_substream_chip(subs);
845 mixart_mgr_t *mgr = chip->mgr;
846 mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
847
848 down(&mgr->setup_mutex);
849
850 snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);
851
852 /* sample rate released */
853 if(--mgr->ref_count_rate == 0) {
854 mgr->sample_rate = 0;
855 }
856
857 /* delete pipe */
858 if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) {
859
860 snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number);
861 }
862
863 stream->pipe = NULL;
864 stream->status = MIXART_STREAM_STATUS_FREE;
865 stream->substream = NULL;
866
867 up(&mgr->setup_mutex);
868 return 0;
869}
870
871
872static snd_pcm_uframes_t snd_mixart_stream_pointer(snd_pcm_substream_t * subs)
873{
874 snd_pcm_runtime_t *runtime = subs->runtime;
875 mixart_stream_t *stream = (mixart_stream_t*)runtime->private_data;
876
877 return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag);
878}
879
880
881
882static snd_pcm_ops_t snd_mixart_playback_ops = {
883 .open = snd_mixart_playback_open,
884 .close = snd_mixart_close,
885 .ioctl = snd_pcm_lib_ioctl,
886 .prepare = snd_mixart_prepare,
887 .hw_params = snd_mixart_hw_params,
888 .hw_free = snd_mixart_hw_free,
889 .trigger = snd_mixart_trigger,
890 .pointer = snd_mixart_stream_pointer,
891};
892
893static snd_pcm_ops_t snd_mixart_capture_ops = {
894 .open = snd_mixart_capture_open,
895 .close = snd_mixart_close,
896 .ioctl = snd_pcm_lib_ioctl,
897 .prepare = snd_mixart_prepare,
898 .hw_params = snd_mixart_hw_params,
899 .hw_free = snd_mixart_hw_free,
900 .trigger = snd_mixart_trigger,
901 .pointer = snd_mixart_stream_pointer,
902};
903
904static void preallocate_buffers(mixart_t *chip, snd_pcm_t *pcm)
905{
906#if 0
907 snd_pcm_substream_t *subs;
908 int stream;
909
910 for (stream = 0; stream < 2; stream++) {
911 int idx = 0;
912 for (subs = pcm->streams[stream].substream; subs; subs = subs->next, idx++)
913 /* set up the unique device id with the chip index */
914 subs->dma_device.id = subs->pcm->device << 16 |
915 subs->stream << 8 | (subs->number + 1) |
916 (chip->chip_idx + 1) << 24;
917 }
918#endif
919 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
920 snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024);
921}
922
923/*
924 */
925static int snd_mixart_pcm_analog(mixart_t *chip)
926{
927 int err;
928 snd_pcm_t *pcm;
929 char name[32];
930
931 sprintf(name, "miXart analog %d", chip->chip_idx);
932 if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG,
933 MIXART_PLAYBACK_STREAMS,
934 MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
935 snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx);
936 return err;
937 }
938
939 pcm->private_data = chip;
940
941 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
942 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
943
944 pcm->info_flags = 0;
945 strcpy(pcm->name, name);
946
947 preallocate_buffers(chip, pcm);
948
949 chip->pcm = pcm;
950 return 0;
951}
952
953
954/*
955 */
956static int snd_mixart_pcm_digital(mixart_t *chip)
957{
958 int err;
959 snd_pcm_t *pcm;
960 char name[32];
961
962 sprintf(name, "miXart AES/EBU %d", chip->chip_idx);
963 if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
964 MIXART_PLAYBACK_STREAMS,
965 MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
966 snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx);
967 return err;
968 }
969
970 pcm->private_data = chip;
971
972 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
973 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
974
975 pcm->info_flags = 0;
976 strcpy(pcm->name, name);
977
978 preallocate_buffers(chip, pcm);
979
980 chip->pcm_dig = pcm;
981 return 0;
982}
983
984static int snd_mixart_chip_free(mixart_t *chip)
985{
986 kfree(chip);
987 return 0;
988}
989
990static int snd_mixart_chip_dev_free(snd_device_t *device)
991{
992 mixart_t *chip = device->device_data;
993 return snd_mixart_chip_free(chip);
994}
995
996
997/*
998 */
999static int __devinit snd_mixart_create(mixart_mgr_t *mgr, snd_card_t *card, int idx)
1000{
1001 int err;
1002 mixart_t *chip;
1003 static snd_device_ops_t ops = {
1004 .dev_free = snd_mixart_chip_dev_free,
1005 };
1006
1007 mgr->chip[idx] = chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
1008 if (! chip) {
1009 snd_printk(KERN_ERR "cannot allocate chip\n");
1010 return -ENOMEM;
1011 }
1012
1013 chip->card = card;
1014 chip->chip_idx = idx;
1015 chip->mgr = mgr;
1016
1017 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
1018 snd_mixart_chip_free(chip);
1019 return err;
1020 }
1021
1022 snd_card_set_dev(card, &mgr->pci->dev);
1023
1024 return 0;
1025}
1026
1027int snd_mixart_create_pcm(mixart_t* chip)
1028{
1029 int err;
1030
1031 err = snd_mixart_pcm_analog(chip);
1032 if (err < 0)
1033 return err;
1034
1035 if(chip->mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
1036
1037 err = snd_mixart_pcm_digital(chip);
1038 if (err < 0)
1039 return err;
1040 }
1041 return err;
1042}
1043
1044
1045/*
1046 * release all the cards assigned to a manager instance
1047 */
1048static int snd_mixart_free(mixart_mgr_t *mgr)
1049{
1050 unsigned int i;
1051
1052 for (i = 0; i < mgr->num_cards; i++) {
1053 if (mgr->chip[i])
1054 snd_card_free(mgr->chip[i]->card);
1055 }
1056
1057 /* stop mailbox */
1058 snd_mixart_exit_mailbox(mgr);
1059
1060 /* release irq */
1061 if (mgr->irq >= 0)
1062 free_irq(mgr->irq, (void *)mgr);
1063
1064 /* reset board if some firmware was loaded */
1065 if(mgr->dsp_loaded) {
1066 snd_mixart_reset_board(mgr);
1067 snd_printdd("reset miXart !\n");
1068 }
1069
1070 /* release the i/o ports */
1071 for (i = 0; i < 2; i++) {
1072 if (mgr->mem[i].virt)
1073 iounmap(mgr->mem[i].virt);
1074 }
1075 pci_release_regions(mgr->pci);
1076
1077 /* free flowarray */
1078 if(mgr->flowinfo.area) {
1079 snd_dma_free_pages(&mgr->flowinfo);
1080 mgr->flowinfo.area = NULL;
1081 }
1082 /* free bufferarray */
1083 if(mgr->bufferinfo.area) {
1084 snd_dma_free_pages(&mgr->bufferinfo);
1085 mgr->bufferinfo.area = NULL;
1086 }
1087
1088 pci_disable_device(mgr->pci);
1089 kfree(mgr);
1090 return 0;
1091}
1092
1093/*
1094 * proc interface
1095 */
1096static long long snd_mixart_BA0_llseek(snd_info_entry_t *entry,
1097 void *private_file_data,
1098 struct file *file,
1099 long long offset,
1100 int orig)
1101{
1102 offset = offset & ~3; /* 4 bytes aligned */
1103
1104 switch(orig) {
1105 case 0: /* SEEK_SET */
1106 file->f_pos = offset;
1107 break;
1108 case 1: /* SEEK_CUR */
1109 file->f_pos += offset;
1110 break;
1111 case 2: /* SEEK_END, offset is negative */
1112 file->f_pos = MIXART_BA0_SIZE + offset;
1113 break;
1114 default:
1115 return -EINVAL;
1116 }
1117 if(file->f_pos > MIXART_BA0_SIZE)
1118 file->f_pos = MIXART_BA0_SIZE;
1119 return file->f_pos;
1120}
1121
1122static long long snd_mixart_BA1_llseek(snd_info_entry_t *entry,
1123 void *private_file_data,
1124 struct file *file,
1125 long long offset,
1126 int orig)
1127{
1128 offset = offset & ~3; /* 4 bytes aligned */
1129
1130 switch(orig) {
1131 case 0: /* SEEK_SET */
1132 file->f_pos = offset;
1133 break;
1134 case 1: /* SEEK_CUR */
1135 file->f_pos += offset;
1136 break;
1137 case 2: /* SEEK_END, offset is negative */
1138 file->f_pos = MIXART_BA1_SIZE + offset;
1139 break;
1140 default:
1141 return -EINVAL;
1142 }
1143 if(file->f_pos > MIXART_BA1_SIZE)
1144 file->f_pos = MIXART_BA1_SIZE;
1145 return file->f_pos;
1146}
1147
1148/*
1149 mixart_BA0 proc interface for BAR 0 - read callback
1150 */
1151static long snd_mixart_BA0_read(snd_info_entry_t *entry, void *file_private_data,
1152 struct file *file, char __user *buf,
1153 unsigned long count, unsigned long pos)
1154{
1155 mixart_mgr_t *mgr = entry->private_data;
1156
1157 count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
1158 if(count <= 0)
1159 return 0;
1160 if(pos + count > MIXART_BA0_SIZE)
1161 count = (long)(MIXART_BA0_SIZE - pos);
1162 if(copy_to_user_fromio(buf, MIXART_MEM( mgr, pos ), count))
1163 return -EFAULT;
1164 return count;
1165}
1166
1167/*
1168 mixart_BA1 proc interface for BAR 1 - read callback
1169 */
1170static long snd_mixart_BA1_read(snd_info_entry_t *entry, void *file_private_data,
1171 struct file *file, char __user *buf,
1172 unsigned long count, unsigned long pos)
1173{
1174 mixart_mgr_t *mgr = entry->private_data;
1175
1176 count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
1177 if(count <= 0)
1178 return 0;
1179 if(pos + count > MIXART_BA1_SIZE)
1180 count = (long)(MIXART_BA1_SIZE - pos);
1181 if(copy_to_user_fromio(buf, MIXART_REG( mgr, pos ), count))
1182 return -EFAULT;
1183 return count;
1184}
1185
1186static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = {
1187 .read = snd_mixart_BA0_read,
1188 .llseek = snd_mixart_BA0_llseek
1189};
1190
1191static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = {
1192 .read = snd_mixart_BA1_read,
1193 .llseek = snd_mixart_BA1_llseek
1194};
1195
1196
1197static void snd_mixart_proc_read(snd_info_entry_t *entry,
1198 snd_info_buffer_t * buffer)
1199{
1200 mixart_t *chip = entry->private_data;
1201 u32 ref;
1202
1203 snd_iprintf(buffer, "Digigram miXart (alsa card %d)\n\n", chip->chip_idx);
1204
1205 /* stats available when embedded OS is running */
1206 if (chip->mgr->dsp_loaded & ( 1 << MIXART_MOTHERBOARD_ELF_INDEX)) {
1207 snd_iprintf(buffer, "- hardware -\n");
1208 switch (chip->mgr->board_type ) {
1209 case MIXART_DAUGHTER_TYPE_NONE : snd_iprintf(buffer, "\tmiXart8 (no daughter board)\n\n"); break;
1210 case MIXART_DAUGHTER_TYPE_AES : snd_iprintf(buffer, "\tmiXart8 AES/EBU\n\n"); break;
1211 case MIXART_DAUGHTER_TYPE_COBRANET : snd_iprintf(buffer, "\tmiXart8 Cobranet\n\n"); break;
1212 default: snd_iprintf(buffer, "\tUNKNOWN!\n\n"); break;
1213 }
1214
1215 snd_iprintf(buffer, "- system load -\n");
1216
1217 /* get perf reference */
1218
1219 ref = readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET));
1220
1221 if (ref) {
1222 u32 mailbox = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET)) / ref;
1223 u32 streaming = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET)) / ref;
1224 u32 interr = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET)) / ref;
1225
1226 snd_iprintf(buffer, "\tstreaming : %d\n", streaming);
1227 snd_iprintf(buffer, "\tmailbox : %d\n", mailbox);
1228 snd_iprintf(buffer, "\tinterrups handling : %d\n\n", interr);
1229 }
1230 } /* endif elf loaded */
1231}
1232
1233static void __devinit snd_mixart_proc_init(mixart_t *chip)
1234{
1235 snd_info_entry_t *entry;
1236
1237 /* text interface to read perf and temp meters */
1238 if (! snd_card_proc_new(chip->card, "board_info", &entry)) {
1239 entry->private_data = chip;
1240 entry->c.text.read_size = 1024;
1241 entry->c.text.read = snd_mixart_proc_read;
1242 }
1243
1244 if (! snd_card_proc_new(chip->card, "mixart_BA0", &entry)) {
1245 entry->content = SNDRV_INFO_CONTENT_DATA;
1246 entry->private_data = chip->mgr;
1247 entry->c.ops = &snd_mixart_proc_ops_BA0;
1248 entry->size = MIXART_BA0_SIZE;
1249 }
1250 if (! snd_card_proc_new(chip->card, "mixart_BA1", &entry)) {
1251 entry->content = SNDRV_INFO_CONTENT_DATA;
1252 entry->private_data = chip->mgr;
1253 entry->c.ops = &snd_mixart_proc_ops_BA1;
1254 entry->size = MIXART_BA1_SIZE;
1255 }
1256}
1257/* end of proc interface */
1258
1259
1260/*
1261 * probe function - creates the card manager
1262 */
1263static int __devinit snd_mixart_probe(struct pci_dev *pci,
1264 const struct pci_device_id *pci_id)
1265{
1266 static int dev;
1267 mixart_mgr_t *mgr;
1268 unsigned int i;
1269 int err;
1270 size_t size;
1271
1272 /*
1273 */
1274 if (dev >= SNDRV_CARDS)
1275 return -ENODEV;
1276 if (! enable[dev]) {
1277 dev++;
1278 return -ENOENT;
1279 }
1280
1281 /* enable PCI device */
1282 if ((err = pci_enable_device(pci)) < 0)
1283 return err;
1284 pci_set_master(pci);
1285
1286 /* check if we can restrict PCI DMA transfers to 32 bits */
1287 if (pci_set_dma_mask(pci, 0xffffffff) < 0) {
1288 snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
1289 pci_disable_device(pci);
1290 return -ENXIO;
1291 }
1292
1293 /*
1294 */
1295 mgr = kcalloc(1, sizeof(*mgr), GFP_KERNEL);
1296 if (! mgr) {
1297 pci_disable_device(pci);
1298 return -ENOMEM;
1299 }
1300
1301 mgr->pci = pci;
1302 mgr->irq = -1;
1303
1304 /* resource assignment */
1305 if ((err = pci_request_regions(pci, CARD_NAME)) < 0) {
1306 kfree(mgr);
1307 pci_disable_device(pci);
1308 return err;
1309 }
1310 for (i = 0; i < 2; i++) {
1311 mgr->mem[i].phys = pci_resource_start(pci, i);
1312 mgr->mem[i].virt = ioremap_nocache(mgr->mem[i].phys,
1313 pci_resource_len(pci, i));
1314 }
1315
1316 if (request_irq(pci->irq, snd_mixart_interrupt, SA_INTERRUPT|SA_SHIRQ, CARD_NAME, (void *)mgr)) {
1317 snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
1318 snd_mixart_free(mgr);
1319 return -EBUSY;
1320 }
1321 mgr->irq = pci->irq;
1322
1323 sprintf(mgr->shortname, "Digigram miXart");
1324 sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq);
1325
1326 /* ISR spinlock */
1327 spin_lock_init(&mgr->lock);
1328
1329 /* init mailbox */
1330 mgr->msg_fifo_readptr = 0;
1331 mgr->msg_fifo_writeptr = 0;
1332
1333 spin_lock_init(&mgr->msg_lock);
1334 init_MUTEX(&mgr->msg_mutex);
1335 init_waitqueue_head(&mgr->msg_sleep);
1336 atomic_set(&mgr->msg_processed, 0);
1337
1338 /* init setup mutex*/
1339 init_MUTEX(&mgr->setup_mutex);
1340
1341 /* init message taslket */
1342 tasklet_init( &mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);
1343
1344 /* card assignment */
1345 mgr->num_cards = MIXART_MAX_CARDS; /* 4 FIXME: configurable? */
1346 for (i = 0; i < mgr->num_cards; i++) {
1347 snd_card_t *card;
1348 char tmpid[16];
1349 int idx;
1350
1351 if (index[dev] < 0)
1352 idx = index[dev];
1353 else
1354 idx = index[dev] + i;
1355 snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : "MIXART", i);
1356 card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
1357
1358 if (! card) {
1359 snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
1360 snd_mixart_free(mgr);
1361 return -ENOMEM;
1362 }
1363
1364 strcpy(card->driver, CARD_NAME);
1365 sprintf(card->shortname, "%s [PCM #%d]", mgr->shortname, i);
1366 sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i);
1367
1368 if ((err = snd_mixart_create(mgr, card, i)) < 0) {
1369 snd_mixart_free(mgr);
1370 return err;
1371 }
1372
1373 if(i==0) {
1374 /* init proc interface only for chip0 */
1375 snd_mixart_proc_init(mgr->chip[i]);
1376 }
1377
1378 if ((err = snd_card_register(card)) < 0) {
1379 snd_mixart_free(mgr);
1380 return err;
1381 }
1382 }
1383
1384 /* init firmware status (mgr->dsp_loaded reset in hwdep_new) */
1385 mgr->board_type = MIXART_DAUGHTER_TYPE_NONE;
1386
1387 /* create array of streaminfo */
1388 size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_flowinfo_t)) );
1389 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
1390 size, &mgr->flowinfo) < 0) {
1391 snd_mixart_free(mgr);
1392 return -ENOMEM;
1393 }
1394 /* init streaminfo_array */
1395 memset(mgr->flowinfo.area, 0, size);
1396
1397 /* create array of bufferinfo */
1398 size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_bufferinfo_t)) );
1399 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
1400 size, &mgr->bufferinfo) < 0) {
1401 snd_mixart_free(mgr);
1402 return -ENOMEM;
1403 }
1404 /* init bufferinfo_array */
1405 memset(mgr->bufferinfo.area, 0, size);
1406
1407 /* set up firmware */
1408 err = snd_mixart_setup_firmware(mgr);
1409 if (err < 0) {
1410 snd_mixart_free(mgr);
1411 return err;
1412 }
1413
1414 pci_set_drvdata(pci, mgr);
1415 dev++;
1416 return 0;
1417}
1418
1419static void __devexit snd_mixart_remove(struct pci_dev *pci)
1420{
1421 snd_mixart_free(pci_get_drvdata(pci));
1422 pci_set_drvdata(pci, NULL);
1423}
1424
1425static struct pci_driver driver = {
1426 .name = "Digigram miXart",
1427 .id_table = snd_mixart_ids,
1428 .probe = snd_mixart_probe,
1429 .remove = __devexit_p(snd_mixart_remove),
1430};
1431
1432static int __init alsa_card_mixart_init(void)
1433{
1434 return pci_module_init(&driver);
1435}
1436
1437static void __exit alsa_card_mixart_exit(void)
1438{
1439 pci_unregister_driver(&driver);
1440}
1441
1442module_init(alsa_card_mixart_init)
1443module_exit(alsa_card_mixart_exit)
diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h
new file mode 100644
index 000000000000..f87152f94c0e
--- /dev/null
+++ b/sound/pci/mixart/mixart.h
@@ -0,0 +1,242 @@
1/*
2 * Driver for Digigram miXart soundcards
3 *
4 * main header file
5 *
6 * Copyright (c) 2003 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef __SOUND_MIXART_H
24#define __SOUND_MIXART_H
25
26#include <linux/interrupt.h>
27#include <sound/pcm.h>
28
29#define MIXART_DRIVER_VERSION 0x000100 /* 0.1.0 */
30
31
32/*
33 */
34
35#define mixart_t_magic 0xa17a3e01
36#define mixart_mgr_t_magic 0xa17a3e02
37
38typedef struct snd_mixart mixart_t;
39typedef struct snd_mixart_mgr mixart_mgr_t;
40
41typedef struct snd_mixart_stream mixart_stream_t;
42typedef struct snd_mixart_pipe mixart_pipe_t;
43
44typedef struct mixart_bufferinfo mixart_bufferinfo_t;
45typedef struct mixart_flowinfo mixart_flowinfo_t;
46typedef struct mixart_uid mixart_uid_t;
47
48struct mixart_uid
49{
50 u32 object_id;
51 u32 desc;
52};
53
54struct mem_area {
55 unsigned long phys;
56 void __iomem *virt;
57 struct resource *res;
58};
59
60
61typedef struct mixart_route mixart_route_t;
62struct mixart_route {
63 unsigned char connected;
64 unsigned char phase_inv;
65 int volume;
66};
67
68
69/* firmware status codes */
70#define MIXART_MOTHERBOARD_XLX_INDEX 0
71#define MIXART_MOTHERBOARD_ELF_INDEX 1
72#define MIXART_AESEBUBOARD_XLX_INDEX 2
73#define MIXART_HARDW_FILES_MAX_INDEX 3 /* xilinx, elf, AESEBU xilinx */
74
75#define MIXART_MAX_CARDS 4
76#define MSG_FIFO_SIZE 16
77
78#define MIXART_MAX_PHYS_CONNECTORS (MIXART_MAX_CARDS * 2 * 2) /* 4 * stereo * (analog+digital) */
79
80struct snd_mixart_mgr {
81 unsigned int num_cards;
82 mixart_t *chip[MIXART_MAX_CARDS];
83
84 struct pci_dev *pci;
85
86 int irq;
87
88 /* memory-maps */
89 struct mem_area mem[2];
90
91 /* share the name */
92 char shortname[32]; /* short name of this soundcard */
93 char longname[80]; /* name of this soundcard */
94
95 /* message tasklet */
96 struct tasklet_struct msg_taskq;
97
98 /* one and only blocking message or notification may be pending */
99 u32 pending_event;
100 wait_queue_head_t msg_sleep;
101
102 /* messages stored for tasklet */
103 u32 msg_fifo[MSG_FIFO_SIZE];
104 int msg_fifo_readptr;
105 int msg_fifo_writeptr;
106 atomic_t msg_processed; /* number of messages to be processed in takslet */
107
108 spinlock_t lock; /* interrupt spinlock */
109 spinlock_t msg_lock; /* mailbox spinlock */
110 struct semaphore msg_mutex; /* mutex for blocking_requests */
111
112 struct semaphore setup_mutex; /* mutex used in hw_params, open and close */
113
114 /* hardware interface */
115 unsigned int dsp_loaded; /* bit flags of loaded dsp indices */
116 unsigned int board_type; /* read from embedded once elf file is loaded, 250 = miXart8, 251 = with AES, 252 = with Cobranet */
117
118 struct snd_dma_buffer flowinfo;
119 struct snd_dma_buffer bufferinfo;
120
121 mixart_uid_t uid_console_manager;
122 int sample_rate;
123 int ref_count_rate;
124
125 struct semaphore mixer_mutex; /* mutex for mixer */
126
127};
128
129
130#define MIXART_STREAM_STATUS_FREE 0
131#define MIXART_STREAM_STATUS_OPEN 1
132#define MIXART_STREAM_STATUS_RUNNING 2
133#define MIXART_STREAM_STATUS_DRAINING 3
134#define MIXART_STREAM_STATUS_PAUSE 4
135
136#define MIXART_PLAYBACK_STREAMS 4
137#define MIXART_CAPTURE_STREAMS 1
138
139#define MIXART_PCM_ANALOG 0
140#define MIXART_PCM_DIGITAL 1
141#define MIXART_PCM_TOTAL 2
142
143#define MIXART_MAX_STREAM_PER_CARD (MIXART_PCM_TOTAL * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS) )
144
145
146#define MIXART_NOTIFY_CARD_MASK 0xF000
147#define MIXART_NOTIFY_CARD_OFFSET 12
148#define MIXART_NOTIFY_PCM_MASK 0x0F00
149#define MIXART_NOTIFY_PCM_OFFSET 8
150#define MIXART_NOTIFY_CAPT_MASK 0x0080
151#define MIXART_NOTIFY_SUBS_MASK 0x007F
152
153
154struct snd_mixart_stream {
155 snd_pcm_substream_t *substream;
156 mixart_pipe_t *pipe;
157 int pcm_number;
158
159 int status; /* nothing, running, draining */
160
161 u64 abs_period_elapsed; /* last absolute stream position where period_elapsed was called (multiple of runtime->period_size) */
162 u32 buf_periods; /* periods counter in the buffer (< runtime->periods) */
163 u32 buf_period_frag; /* defines with buf_period_pos the exact position in the buffer (< runtime->period_size) */
164
165 int channels;
166};
167
168
169enum mixart_pipe_status {
170 PIPE_UNDEFINED,
171 PIPE_STOPPED,
172 PIPE_RUNNING,
173 PIPE_CLOCK_SET
174};
175
176struct snd_mixart_pipe {
177 mixart_uid_t group_uid; /* id of the pipe, as returned by embedded */
178 int stream_count;
179 mixart_uid_t uid_left_connector; /* UID's for the audio connectors */
180 mixart_uid_t uid_right_connector;
181 enum mixart_pipe_status status;
182 int references; /* number of subs openned */
183 int monitoring; /* pipe used for monitoring issue */
184};
185
186
187struct snd_mixart {
188 snd_card_t *card;
189 mixart_mgr_t *mgr;
190 int chip_idx; /* zero based */
191 snd_hwdep_t *hwdep; /* DSP loader, only for the first card */
192
193 snd_pcm_t *pcm; /* PCM analog i/o */
194 snd_pcm_t *pcm_dig; /* PCM digital i/o */
195
196 /* allocate stereo pipe for instance */
197 mixart_pipe_t pipe_in_ana;
198 mixart_pipe_t pipe_out_ana;
199
200 /* if AES/EBU daughter board is available, additional pipes possible on pcm_dig */
201 mixart_pipe_t pipe_in_dig;
202 mixart_pipe_t pipe_out_dig;
203
204 mixart_stream_t playback_stream[MIXART_PCM_TOTAL][MIXART_PLAYBACK_STREAMS]; /* 0 = pcm, 1 = pcm_dig */
205 mixart_stream_t capture_stream[MIXART_PCM_TOTAL]; /* 0 = pcm, 1 = pcm_dig */
206
207 /* UID's for the physical io's */
208 mixart_uid_t uid_out_analog_physio;
209 mixart_uid_t uid_in_analog_physio;
210
211 int analog_playback_active[2]; /* Mixer : Master Playback active (!mute) */
212 int analog_playback_volume[2]; /* Mixer : Master Playback Volume */
213 int analog_capture_volume[2]; /* Mixer : Master Capture Volume */
214 int digital_playback_active[2*MIXART_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [(analog+AES output)*streams][stereo]*/
215 int digital_playback_volume[2*MIXART_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [(analog+AES output)*streams][stereo]*/
216 int digital_capture_volume[2][2]; /* Mixer : Digital Capture Volume [analog+AES output][stereo] */
217 int monitoring_active[2]; /* Mixer : Monitoring Active */
218 int monitoring_volume[2]; /* Mixer : Monitoring Volume */
219};
220
221struct mixart_bufferinfo
222{
223 u32 buffer_address;
224 u32 reserved[5];
225 u32 available_length;
226 u32 buffer_id;
227};
228
229struct mixart_flowinfo
230{
231 u32 bufferinfo_array_phy_address;
232 u32 reserved[11];
233 u32 bufferinfo_count;
234 u32 capture;
235};
236
237/* exported */
238int snd_mixart_create_pcm(mixart_t* chip);
239mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring);
240int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring);
241
242#endif /* __SOUND_MIXART_H */
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
new file mode 100644
index 000000000000..ba0027f50944
--- /dev/null
+++ b/sound/pci/mixart/mixart_core.c
@@ -0,0 +1,588 @@
1/*
2 * Driver for Digigram miXart soundcards
3 *
4 * low level interface with interrupt handling and mail box implementation
5 *
6 * Copyright (c) 2003 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <sound/driver.h>
24#include <linux/interrupt.h>
25#include <asm/io.h>
26#include <sound/core.h>
27#include "mixart.h"
28#include "mixart_hwdep.h"
29#include "mixart_core.h"
30
31
32#define MSG_TIMEOUT_JIFFIES (400 * HZ) / 1000 /* 400 ms */
33
34#define MSG_DESCRIPTOR_SIZE 0x24
35#define MSG_HEADER_SIZE (MSG_DESCRIPTOR_SIZE + 4)
36
37#define MSG_DEFAULT_SIZE 512
38
39#define MSG_TYPE_MASK 0x00000003 /* mask for following types */
40#define MSG_TYPE_NOTIFY 0 /* embedded -> driver (only notification, do not get_msg() !) */
41#define MSG_TYPE_COMMAND 1 /* driver <-> embedded (a command has no answer) */
42#define MSG_TYPE_REQUEST 2 /* driver -> embedded (request will get an answer back) */
43#define MSG_TYPE_ANSWER 3 /* embedded -> driver */
44#define MSG_CANCEL_NOTIFY_MASK 0x80000000 /* this bit is set for a notification that has been canceled */
45
46
47static int retrieve_msg_frame(mixart_mgr_t *mgr, u32 *msg_frame)
48{
49 /* read the message frame fifo */
50 u32 headptr, tailptr;
51
52 tailptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
53 headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_HEAD));
54
55 if (tailptr == headptr)
56 return 0; /* no message posted */
57
58 snd_assert( tailptr >= MSG_OUTBOUND_POST_STACK, return 0); /* error */
59 snd_assert( tailptr < (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE), return 0); /* error */
60
61 *msg_frame = readl_be(MIXART_MEM(mgr, tailptr));
62
63 /* increment the tail index */
64 tailptr += 4;
65 if( tailptr >= (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
66 tailptr = MSG_OUTBOUND_POST_STACK;
67 writel_be(tailptr, MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
68
69 return 1;
70}
71
72static int get_msg(mixart_mgr_t *mgr, mixart_msg_t *resp, u32 msg_frame_address )
73{
74 unsigned long flags;
75 u32 headptr;
76 u32 size;
77 int err;
78#ifndef __BIG_ENDIAN
79 unsigned int i;
80#endif
81
82 spin_lock_irqsave(&mgr->msg_lock, flags);
83 err = 0;
84
85 /* copy message descriptor from miXart to driver */
86 size = readl_be(MIXART_MEM(mgr, msg_frame_address)); /* size of descriptor + response */
87 resp->message_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 4)); /* dwMessageID */
88 resp->uid.object_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 8)); /* uidDest */
89 resp->uid.desc = readl_be(MIXART_MEM(mgr, msg_frame_address + 12)); /* */
90
91 if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) {
92 err = -EINVAL;
93 snd_printk(KERN_ERR "problem with response size = %d\n", size);
94 goto _clean_exit;
95 }
96 size -= MSG_DESCRIPTOR_SIZE;
97
98 memcpy_fromio(resp->data, MIXART_MEM(mgr, msg_frame_address + MSG_HEADER_SIZE ), size);
99 resp->size = size;
100
101 /* swap if necessary */
102#ifndef __BIG_ENDIAN
103 size /= 4; /* u32 size */
104 for(i=0; i < size; i++) {
105 ((u32*)resp->data)[i] = be32_to_cpu(((u32*)resp->data)[i]);
106 }
107#endif
108
109 /*
110 * free message frame address
111 */
112 headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
113
114 if( (headptr < MSG_OUTBOUND_FREE_STACK) || ( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
115 err = -EINVAL;
116 goto _clean_exit;
117 }
118
119 /* give address back to outbound fifo */
120 writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
121
122 /* increment the outbound free head */
123 headptr += 4;
124 if( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
125 headptr = MSG_OUTBOUND_FREE_STACK;
126
127 writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
128
129 _clean_exit:
130 spin_unlock_irqrestore(&mgr->msg_lock, flags);
131
132 return err;
133}
134
135
136/*
137 * send a message to miXart. return: the msg_frame used for this message
138 */
139/* call with mgr->msg_lock held! */
140static int send_msg( mixart_mgr_t *mgr,
141 mixart_msg_t *msg,
142 int max_answersize,
143 int mark_pending,
144 u32 *msg_event)
145{
146 u32 headptr, tailptr;
147 u32 msg_frame_address;
148 int err, i;
149
150 snd_assert(msg->size % 4 == 0, return -EINVAL);
151
152 err = 0;
153
154 /* get message frame address */
155 tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
156 headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD));
157
158 if (tailptr == headptr) {
159 snd_printk(KERN_ERR "error: no message frame available\n");
160 return -EBUSY;
161 }
162
163 if( (tailptr < MSG_INBOUND_FREE_STACK) || (tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
164 return -EINVAL;
165 }
166
167 msg_frame_address = readl_be(MIXART_MEM(mgr, tailptr));
168 writel(0, MIXART_MEM(mgr, tailptr)); /* set address to zero on this fifo position */
169
170 /* increment the inbound free tail */
171 tailptr += 4;
172 if( tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
173 tailptr = MSG_INBOUND_FREE_STACK;
174
175 writel_be(tailptr, MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
176
177 /* TODO : use memcpy_toio() with intermediate buffer to copy the message */
178
179 /* copy message descriptor to card memory */
180 writel_be( msg->size + MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address) ); /* size of descriptor + request */
181 writel_be( msg->message_id , MIXART_MEM(mgr, msg_frame_address + 4) ); /* dwMessageID */
182 writel_be( msg->uid.object_id, MIXART_MEM(mgr, msg_frame_address + 8) ); /* uidDest */
183 writel_be( msg->uid.desc, MIXART_MEM(mgr, msg_frame_address + 12) ); /* */
184 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 16) ); /* SizeHeader */
185 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 20) ); /* OffsetDLL_T16 */
186 writel_be( msg->size, MIXART_MEM(mgr, msg_frame_address + 24) ); /* SizeDLL_T16 */
187 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 28) ); /* OffsetDLL_DRV */
188 writel_be( 0, MIXART_MEM(mgr, msg_frame_address + 32) ); /* SizeDLL_DRV */
189 writel_be( MSG_DESCRIPTOR_SIZE + max_answersize, MIXART_MEM(mgr, msg_frame_address + 36) ); /* dwExpectedAnswerSize */
190
191 /* copy message data to card memory */
192 for( i=0; i < msg->size; i+=4 ) {
193 writel_be( *(u32*)(msg->data + i), MIXART_MEM(mgr, MSG_HEADER_SIZE + msg_frame_address + i) );
194 }
195
196 if( mark_pending ) {
197 if( *msg_event ) {
198 /* the pending event is the notification we wait for ! */
199 mgr->pending_event = *msg_event;
200 }
201 else {
202 /* the pending event is the answer we wait for (same address than the request)! */
203 mgr->pending_event = msg_frame_address;
204
205 /* copy address back to caller */
206 *msg_event = msg_frame_address;
207 }
208 }
209
210 /* mark the frame as a request (will have an answer) */
211 msg_frame_address |= MSG_TYPE_REQUEST;
212
213 /* post the frame */
214 headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
215
216 if( (headptr < MSG_INBOUND_POST_STACK) || (headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE))) {
217 return -EINVAL;
218 }
219
220 writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
221
222 /* increment the inbound post head */
223 headptr += 4;
224 if( headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
225 headptr = MSG_INBOUND_POST_STACK;
226
227 writel_be(headptr, MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
228
229 return 0;
230}
231
232
233int snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data)
234{
235 mixart_msg_t resp;
236 u32 msg_frame = 0; /* set to 0, so it's no notification to wait for, but the answer */
237 int err;
238 wait_queue_t wait;
239 long timeout;
240
241 down(&mgr->msg_mutex);
242
243 init_waitqueue_entry(&wait, current);
244
245 spin_lock_irq(&mgr->msg_lock);
246 /* send the message */
247 err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */
248 if (err) {
249 spin_unlock_irq(&mgr->msg_lock);
250 up(&mgr->msg_mutex);
251 return err;
252 }
253
254 set_current_state(TASK_UNINTERRUPTIBLE);
255 add_wait_queue(&mgr->msg_sleep, &wait);
256 spin_unlock_irq(&mgr->msg_lock);
257 timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
258 remove_wait_queue(&mgr->msg_sleep, &wait);
259
260 if (! timeout) {
261 /* error - no ack */
262 up(&mgr->msg_mutex);
263 snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame);
264 return -EIO;
265 }
266
267 /* retrieve the answer into the same mixart_msg_t */
268 resp.message_id = 0;
269 resp.uid = (mixart_uid_t){0,0};
270 resp.data = resp_data;
271 resp.size = max_resp_size;
272
273 err = get_msg(mgr, &resp, msg_frame);
274
275 if( request->message_id != resp.message_id )
276 snd_printk(KERN_ERR "REPONSE ERROR!\n");
277
278 up(&mgr->msg_mutex);
279 return err;
280}
281
282
283int snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event)
284{
285 int err;
286 wait_queue_t wait;
287 long timeout;
288
289 snd_assert(notif_event != 0, return -EINVAL);
290 snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL);
291 snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL);
292
293 down(&mgr->msg_mutex);
294
295 init_waitqueue_entry(&wait, current);
296
297 spin_lock_irq(&mgr->msg_lock);
298 /* send the message */
299 err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event); /* send and mark the notification event pending */
300 if(err) {
301 spin_unlock_irq(&mgr->msg_lock);
302 up(&mgr->msg_mutex);
303 return err;
304 }
305
306 set_current_state(TASK_UNINTERRUPTIBLE);
307 add_wait_queue(&mgr->msg_sleep, &wait);
308 spin_unlock_irq(&mgr->msg_lock);
309 timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
310 remove_wait_queue(&mgr->msg_sleep, &wait);
311
312 if (! timeout) {
313 /* error - no ack */
314 up(&mgr->msg_mutex);
315 snd_printk(KERN_ERR "error: notification %x not received\n", notif_event);
316 return -EIO;
317 }
318
319 up(&mgr->msg_mutex);
320 return 0;
321}
322
323
324int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request)
325{
326 u32 message_frame;
327 unsigned long flags;
328 int err;
329
330 /* just send the message (do not mark it as a pending one) */
331 spin_lock_irqsave(&mgr->msg_lock, flags);
332 err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
333 spin_unlock_irqrestore(&mgr->msg_lock, flags);
334
335 /* the answer will be handled by snd_mixart_msg_tasklet() */
336 atomic_inc(&mgr->msg_processed);
337
338 return err;
339}
340
341
342/* common buffer of tasklet and interrupt to send/receive messages */
343static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
344
345
346void snd_mixart_msg_tasklet( unsigned long arg)
347{
348 mixart_mgr_t *mgr = ( mixart_mgr_t*)(arg);
349 mixart_msg_t resp;
350 u32 msg, addr, type;
351 int err;
352
353 spin_lock(&mgr->lock);
354
355 while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) {
356 msg = mgr->msg_fifo[mgr->msg_fifo_readptr];
357 mgr->msg_fifo_readptr++;
358 mgr->msg_fifo_readptr %= MSG_FIFO_SIZE;
359
360 /* process the message ... */
361 addr = msg & ~MSG_TYPE_MASK;
362 type = msg & MSG_TYPE_MASK;
363
364 switch (type) {
365 case MSG_TYPE_ANSWER:
366 /* answer to a message on that we did not wait for (send_msg_nonblock) */
367 resp.message_id = 0;
368 resp.data = mixart_msg_data;
369 resp.size = sizeof(mixart_msg_data);
370 err = get_msg(mgr, &resp, addr);
371 if( err < 0 ) {
372 snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg);
373 break;
374 }
375
376 switch(resp.message_id) {
377 case MSG_STREAM_START_INPUT_STAGE_PACKET:
378 case MSG_STREAM_START_OUTPUT_STAGE_PACKET:
379 case MSG_STREAM_STOP_INPUT_STAGE_PACKET:
380 case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
381 if(mixart_msg_data[0])
382 snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]);
383 break;
384 default:
385 snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
386 msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
387 break;
388 }
389 break;
390 case MSG_TYPE_NOTIFY:
391 /* msg contains no address ! do not get_msg() ! */
392 case MSG_TYPE_COMMAND:
393 /* get_msg() necessary */
394 default:
395 snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg);
396 } /* switch type */
397
398 /* decrement counter */
399 atomic_dec(&mgr->msg_processed);
400
401 } /* while there is a msg in fifo */
402
403 spin_unlock(&mgr->lock);
404}
405
406
407irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
408{
409 mixart_mgr_t *mgr = dev_id;
410 int err;
411 mixart_msg_t resp;
412
413 u32 msg;
414 u32 it_reg;
415
416 spin_lock(&mgr->lock);
417
418 it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
419 if( !(it_reg & MIXART_OIDI) ) {
420 /* this device did not cause the interrupt */
421 spin_unlock(&mgr->lock);
422 return IRQ_NONE;
423 }
424
425 /* mask all interrupts */
426 writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET));
427
428 /* outdoorbell register clear */
429 it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
430 writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
431
432 /* clear interrupt */
433 writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );
434
435 /* process interrupt */
436 while (retrieve_msg_frame(mgr, &msg)) {
437
438 switch (msg & MSG_TYPE_MASK) {
439 case MSG_TYPE_COMMAND:
440 resp.message_id = 0;
441 resp.data = mixart_msg_data;
442 resp.size = sizeof(mixart_msg_data);
443 err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK);
444 if( err < 0 ) {
445 snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg);
446 break;
447 }
448
449 if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) {
450 int i;
451 mixart_timer_notify_t *notify = (mixart_timer_notify_t*)mixart_msg_data;
452
453 for(i=0; i<notify->stream_count; i++) {
454
455 u32 buffer_id = notify->streams[i].buffer_id;
456 unsigned int chip_number = (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET; /* card0 to 3 */
457 unsigned int pcm_number = (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET; /* pcm0 to 3 */
458 unsigned int sub_number = buffer_id & MIXART_NOTIFY_SUBS_MASK; /* 0 to MIXART_PLAYBACK_STREAMS */
459 unsigned int is_capture = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0); /* playback == 0 / capture == 1 */
460
461 mixart_t *chip = mgr->chip[chip_number];
462 mixart_stream_t *stream;
463
464 if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) {
465 snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
466 buffer_id, notify->streams[i].sample_pos_low_part);
467 break;
468 }
469
470 if (is_capture)
471 stream = &chip->capture_stream[pcm_number];
472 else
473 stream = &chip->playback_stream[pcm_number][sub_number];
474
475 if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) {
476 snd_pcm_runtime_t *runtime = stream->substream->runtime;
477 int elapsed = 0;
478 u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32;
479 sample_count |= notify->streams[i].sample_pos_low_part;
480
481 while (1) {
482 u64 new_elapse_pos = stream->abs_period_elapsed + runtime->period_size;
483
484 if (new_elapse_pos > sample_count) {
485 break; /* while */
486 }
487 else {
488 elapsed = 1;
489 stream->buf_periods++;
490 if (stream->buf_periods >= runtime->periods)
491 stream->buf_periods = 0;
492
493 stream->abs_period_elapsed = new_elapse_pos;
494 }
495 }
496 stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );
497
498 if(elapsed) {
499 spin_unlock(&mgr->lock);
500 snd_pcm_period_elapsed(stream->substream);
501 spin_lock(&mgr->lock);
502 }
503 }
504 }
505 break;
506 }
507 if(resp.message_id == MSG_SERVICES_REPORT_TRACES) {
508 if(resp.size > 1) {
509#ifndef __BIG_ENDIAN
510 /* Traces are text: the swapped msg_data has to be swapped back ! */
511 int i;
512 for(i=0; i<(resp.size/4); i++) {
513 (mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
514 }
515#endif
516 ((char*)mixart_msg_data)[resp.size - 1] = 0;
517 snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data);
518 }
519 break;
520 }
521
522 snd_printdd("command %x not handled\n", resp.message_id);
523 break;
524
525 case MSG_TYPE_NOTIFY:
526 if(msg & MSG_CANCEL_NOTIFY_MASK) {
527 msg &= ~MSG_CANCEL_NOTIFY_MASK;
528 snd_printk(KERN_ERR "canceled notification %x !\n", msg);
529 }
530 /* no break, continue ! */
531 case MSG_TYPE_ANSWER:
532 /* answer or notification to a message we are waiting for*/
533 spin_lock(&mgr->msg_lock);
534 if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
535 wake_up(&mgr->msg_sleep);
536 mgr->pending_event = 0;
537 }
538 /* answer to a message we did't want to wait for */
539 else {
540 mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
541 mgr->msg_fifo_writeptr++;
542 mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
543 tasklet_hi_schedule(&mgr->msg_taskq);
544 }
545 spin_unlock(&mgr->msg_lock);
546 break;
547 case MSG_TYPE_REQUEST:
548 default:
549 snd_printdd("interrupt received request %x\n", msg);
550 /* TODO : are there things to do here ? */
551 break;
552 } /* switch on msg type */
553 } /* while there are msgs */
554
555 /* allow interrupt again */
556 writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
557
558 spin_unlock(&mgr->lock);
559
560 return IRQ_HANDLED;
561}
562
563
564void snd_mixart_init_mailbox(mixart_mgr_t *mgr)
565{
566 writel( 0, MIXART_MEM( mgr, MSG_HOST_RSC_PROTECTION ) );
567 writel( 0, MIXART_MEM( mgr, MSG_AGENT_RSC_PROTECTION ) );
568
569 /* allow outbound messagebox to generate interrupts */
570 if(mgr->irq >= 0) {
571 writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
572 }
573 return;
574}
575
576void snd_mixart_exit_mailbox(mixart_mgr_t *mgr)
577{
578 /* no more interrupts on outbound messagebox */
579 writel_le( MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
580 return;
581}
582
583void snd_mixart_reset_board(mixart_mgr_t *mgr)
584{
585 /* reset miXart */
586 writel_be( 1, MIXART_REG(mgr, MIXART_BA1_BRUTAL_RESET_OFFSET) );
587 return;
588}
diff --git a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h
new file mode 100644
index 000000000000..99450eba15c0
--- /dev/null
+++ b/sound/pci/mixart/mixart_core.h
@@ -0,0 +1,607 @@
1/*
2 * Driver for Digigram miXart soundcards
3 *
4 * low level interface with interrupt handling and mail box implementation
5 *
6 * Copyright (c) 2003 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef __SOUND_MIXART_CORE_H
24#define __SOUND_MIXART_CORE_H
25
26
27enum mixart_message_id {
28 MSG_CONNECTOR_GET_AUDIO_INFO = 0x050008,
29 MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL = 0x050009,
30 MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL = 0x05000A,
31
32 MSG_CONSOLE_MANAGER = 0x070000,
33 MSG_CONSOLE_GET_CLOCK_UID = 0x070003,
34
35 MSG_PHYSICALIO_SET_LEVEL = 0x0F0008,
36
37 MSG_STREAM_ADD_INPUT_GROUP = 0x130000,
38 MSG_STREAM_ADD_OUTPUT_GROUP = 0x130001,
39 MSG_STREAM_DELETE_GROUP = 0x130004,
40 MSG_STREAM_START_STREAM_GRP_PACKET = 0x130006,
41 MSG_STREAM_START_INPUT_STAGE_PACKET = 0x130007,
42 MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130008,
43 MSG_STREAM_STOP_STREAM_GRP_PACKET = 0x130009,
44 MSG_STREAM_STOP_INPUT_STAGE_PACKET = 0x13000A,
45 MSG_STREAM_STOP_OUTPUT_STAGE_PACKET = 0x13000B,
46 MSG_STREAM_SET_INPUT_STAGE_PARAM = 0x13000F,
47 MSG_STREAM_SET_OUTPUT_STAGE_PARAM = 0x130010,
48 MSG_STREAM_SET_IN_AUDIO_LEVEL = 0x130015,
49 MSG_STREAM_SET_OUT_STREAM_LEVEL = 0x130017,
50
51 MSG_SYSTEM_FIRST_ID = 0x160000,
52 MSG_SYSTEM_ENUM_PHYSICAL_IO = 0x16000E,
53 MSG_SYSTEM_ENUM_PLAY_CONNECTOR = 0x160017,
54 MSG_SYSTEM_ENUM_RECORD_CONNECTOR = 0x160018,
55 MSG_SYSTEM_WAIT_SYNCHRO_CMD = 0x16002C,
56 MSG_SYSTEM_SEND_SYNCHRO_CMD = 0x16002D,
57
58 MSG_SERVICES_TIMER_NOTIFY = 0x1D0404,
59 MSG_SERVICES_REPORT_TRACES = 0x1D0700,
60
61 MSG_CLOCK_CHECK_PROPERTIES = 0x200001,
62 MSG_CLOCK_SET_PROPERTIES = 0x200002,
63};
64
65
66typedef struct mixart_msg mixart_msg_t;
67struct mixart_msg
68{
69 u32 message_id;
70 mixart_uid_t uid;
71 void* data;
72 size_t size;
73};
74
75/* structs used to communicate with miXart */
76
77typedef struct mixart_enum_connector_resp mixart_enum_connector_resp_t;
78struct mixart_enum_connector_resp
79{
80 u32 error_code;
81 u32 first_uid_offset;
82 u32 uid_count;
83 u32 current_uid_index;
84 mixart_uid_t uid[MIXART_MAX_PHYS_CONNECTORS];
85} __attribute__((packed));
86
87
88/* used for following struct */
89#define MIXART_FLOAT_P_22_0_TO_HEX 0x41b00000 /* 22.0f */
90#define MIXART_FLOAT_M_20_0_TO_HEX 0xc1a00000 /* -20.0f */
91#define MIXART_FLOAT____0_0_TO_HEX 0x00000000 /* 0.0f */
92
93typedef struct mixart_audio_info_req mixart_audio_info_req_t;
94struct mixart_audio_info_req
95{
96 u32 line_max_level; /* float */
97 u32 micro_max_level; /* float */
98 u32 cd_max_level; /* float */
99} __attribute__((packed));
100
101typedef struct mixart_analog_hw_info mixart_analog_hw_info_t;
102struct mixart_analog_hw_info
103{
104 u32 is_present;
105 u32 hw_connection_type;
106 u32 max_level; /* float */
107 u32 min_var_level; /* float */
108 u32 max_var_level; /* float */
109 u32 step_var_level; /* float */
110 u32 fix_gain; /* float */
111 u32 zero_var; /* float */
112} __attribute__((packed));
113
114typedef struct mixart_digital_hw_info mixart_digital_hw_info_t;
115struct mixart_digital_hw_info
116{
117 u32 hw_connection_type;
118 u32 presence;
119 u32 clock;
120 u32 reserved;
121} __attribute__((packed));
122
123typedef struct mixart_analog_info mixart_analog_info_t;
124struct mixart_analog_info
125{
126 u32 type_mask;
127 mixart_analog_hw_info_t micro_info;
128 mixart_analog_hw_info_t line_info;
129 mixart_analog_hw_info_t cd_info;
130 u32 analog_level_present;
131} __attribute__((packed));
132
133typedef struct mixart_digital_info mixart_digital_info_t;
134struct mixart_digital_info
135{
136 u32 type_mask;
137 mixart_digital_hw_info_t aes_info;
138 mixart_digital_hw_info_t adat_info;
139} __attribute__((packed));
140
141typedef struct mixart_audio_info mixart_audio_info_t;
142struct mixart_audio_info
143{
144 u32 clock_type_mask;
145 mixart_analog_info_t analog_info;
146 mixart_digital_info_t digital_info;
147} __attribute__((packed));
148
149typedef struct mixart_audio_info_resp mixart_audio_info_resp_t;
150struct mixart_audio_info_resp
151{
152 u32 txx_status;
153 mixart_audio_info_t info;
154} __attribute__((packed));
155
156
157/* used for nb_bytes_max_per_sample */
158#define MIXART_FLOAT_P__4_0_TO_HEX 0x40800000 /* +4.0f */
159#define MIXART_FLOAT_P__8_0_TO_HEX 0x41000000 /* +8.0f */
160
161typedef struct mixart_stream_info mixart_stream_info_t;
162struct mixart_stream_info
163{
164 u32 size_max_byte_frame;
165 u32 size_max_sample_frame;
166 u32 nb_bytes_max_per_sample; /* float */
167} __attribute__((packed));
168
169/* MSG_STREAM_ADD_INPUT_GROUP */
170/* MSG_STREAM_ADD_OUTPUT_GROUP */
171
172typedef struct mixart_streaming_group_req mixart_streaming_group_req_t;
173struct mixart_streaming_group_req
174{
175 u32 stream_count;
176 u32 channel_count;
177 u32 user_grp_number;
178 u32 first_phys_audio;
179 u32 latency;
180 mixart_stream_info_t stream_info[32];
181 mixart_uid_t connector;
182 u32 flow_entry[32];
183} __attribute__((packed));
184
185typedef struct mixart_stream_desc mixart_stream_desc_t;
186struct mixart_stream_desc
187{
188 mixart_uid_t stream_uid;
189 u32 stream_desc;
190} __attribute__((packed));
191
192typedef struct mixart_streaming_group mixart_streaming_group_t;
193struct mixart_streaming_group
194{
195 u32 status;
196 mixart_uid_t group;
197 u32 pipe_desc;
198 u32 stream_count;
199 mixart_stream_desc_t stream[32];
200} __attribute__((packed));
201
202/* MSG_STREAM_DELETE_GROUP */
203
204/* request : mixart_uid_t group */
205
206typedef struct mixart_delete_group_resp mixart_delete_group_resp_t;
207struct mixart_delete_group_resp
208{
209 u32 status;
210 u32 unused[2];
211} __attribute__((packed));
212
213
214/* MSG_STREAM_START_INPUT_STAGE_PACKET = 0x130000 + 7,
215 MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130000 + 8,
216 MSG_STREAM_STOP_INPUT_STAGE_PACKET = 0x130000 + 10,
217 MSG_STREAM_STOP_OUTPUT_STAGE_PACKET = 0x130000 + 11,
218 */
219
220typedef struct mixart_fx_couple_uid mixart_fx_couple_uid_t;
221struct mixart_fx_couple_uid
222{
223 mixart_uid_t uid_fx_code;
224 mixart_uid_t uid_fx_data;
225} __attribute__((packed));
226
227typedef struct mixart_txx_stream_desc mixart_txx_stream_desc_t;
228struct mixart_txx_stream_desc
229{
230 mixart_uid_t uid_pipe;
231 u32 stream_idx;
232 u32 fx_number;
233 mixart_fx_couple_uid_t uid_fx[4];
234} __attribute__((packed));
235
236typedef struct mixart_flow_info mixart_flow_info_t;
237struct mixart_flow_info
238{
239 mixart_txx_stream_desc_t stream_desc;
240 u32 flow_entry;
241 u32 flow_phy_addr;
242} __attribute__((packed));
243
244typedef struct mixart_stream_state_req mixart_stream_state_req_t;
245struct mixart_stream_state_req
246{
247 u32 delayed;
248 u64 scheduler;
249 u32 reserved4np[3];
250 u32 stream_count; /* set to 1 for instance */
251 mixart_flow_info_t stream_info; /* could be an array[stream_count] */
252} __attribute__((packed));
253
254/* MSG_STREAM_START_STREAM_GRP_PACKET = 0x130000 + 6
255 MSG_STREAM_STOP_STREAM_GRP_PACKET = 0x130000 + 9
256 */
257
258typedef struct mixart_group_state_req mixart_group_state_req_t;
259struct mixart_group_state_req
260{
261 u32 delayed;
262 u64 scheduler;
263 u32 reserved4np[2];
264 u32 pipe_count; /* set to 1 for instance */
265 mixart_uid_t pipe_uid[1]; /* could be an array[pipe_count] */
266} __attribute__((packed));
267
268typedef struct mixart_group_state_resp mixart_group_state_resp_t;
269struct mixart_group_state_resp
270{
271 u32 txx_status;
272 u64 scheduler;
273} __attribute__((packed));
274
275
276
277/* Structures used by the MSG_SERVICES_TIMER_NOTIFY command */
278
279typedef struct mixart_sample_pos mixart_sample_pos_t;
280struct mixart_sample_pos
281{
282 u32 buffer_id;
283 u32 validity;
284 u32 sample_pos_high_part;
285 u32 sample_pos_low_part;
286} __attribute__((packed));
287
288typedef struct mixart_timer_notify mixart_timer_notify_t;
289struct mixart_timer_notify
290{
291 u32 stream_count;
292 mixart_sample_pos_t streams[MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS];
293} __attribute__((packed));
294
295
296/* MSG_CONSOLE_GET_CLOCK_UID = 0x070003,
297 */
298
299/* request is a uid with desc = MSG_CONSOLE_MANAGER | cardindex */
300
301typedef struct mixart_return_uid mixart_return_uid_t;
302struct mixart_return_uid
303{
304 u32 error_code;
305 mixart_uid_t uid;
306} __attribute__((packed));
307
308/* MSG_CLOCK_CHECK_PROPERTIES = 0x200001,
309 MSG_CLOCK_SET_PROPERTIES = 0x200002,
310*/
311
312enum mixart_clock_generic_type {
313 CGT_NO_CLOCK,
314 CGT_INTERNAL_CLOCK,
315 CGT_PROGRAMMABLE_CLOCK,
316 CGT_INTERNAL_ENSLAVED_CLOCK,
317 CGT_EXTERNAL_CLOCK,
318 CGT_CURRENT_CLOCK
319};
320
321enum mixart_clock_mode {
322 CM_UNDEFINED,
323 CM_MASTER,
324 CM_SLAVE,
325 CM_STANDALONE,
326 CM_NOT_CONCERNED
327};
328
329
330typedef struct mixart_clock_properties mixart_clock_properties_t;
331struct mixart_clock_properties
332{
333 u32 error_code;
334 u32 validation_mask;
335 u32 frequency;
336 u32 reference_frequency;
337 u32 clock_generic_type;
338 u32 clock_mode;
339 mixart_uid_t uid_clock_source;
340 mixart_uid_t uid_event_source;
341 u32 event_mode;
342 u32 synchro_signal_presence;
343 u32 format;
344 u32 board_mask;
345 u32 nb_callers; /* set to 1 (see below) */
346 mixart_uid_t uid_caller[1];
347} __attribute__((packed));
348
349typedef struct mixart_clock_properties_resp mixart_clock_properties_resp_t;
350struct mixart_clock_properties_resp
351{
352 u32 status;
353 u32 clock_mode;
354} __attribute__((packed));
355
356
357/* MSG_STREAM_SET_INPUT_STAGE_PARAM = 0x13000F */
358/* MSG_STREAM_SET_OUTPUT_STAGE_PARAM = 0x130010 */
359
360enum mixart_coding_type {
361 CT_NOT_DEFINED,
362 CT_LINEAR,
363 CT_MPEG_L1,
364 CT_MPEG_L2,
365 CT_MPEG_L3,
366 CT_MPEG_L3_LSF,
367 CT_GSM
368};
369enum mixart_sample_type {
370 ST_NOT_DEFINED,
371 ST_FLOATING_POINT_32BE,
372 ST_FLOATING_POINT_32LE,
373 ST_FLOATING_POINT_64BE,
374 ST_FLOATING_POINT_64LE,
375 ST_FIXED_POINT_8,
376 ST_FIXED_POINT_16BE,
377 ST_FIXED_POINT_16LE,
378 ST_FIXED_POINT_24BE,
379 ST_FIXED_POINT_24LE,
380 ST_FIXED_POINT_32BE,
381 ST_FIXED_POINT_32LE,
382 ST_INTEGER_8,
383 ST_INTEGER_16BE,
384 ST_INTEGER_16LE,
385 ST_INTEGER_24BE,
386 ST_INTEGER_24LE,
387 ST_INTEGER_32BE,
388 ST_INTEGER_32LE
389};
390
391typedef struct mixart_stream_param_desc mixart_stream_param_desc_t;
392struct mixart_stream_param_desc
393{
394 u32 coding_type; /* use enum mixart_coding_type */
395 u32 sample_type; /* use enum mixart_sample_type */
396
397 union {
398 struct {
399 u32 linear_endian_ness;
400 u32 linear_bits;
401 u32 is_signed;
402 u32 is_float;
403 } linear_format_info;
404
405 struct {
406 u32 mpeg_layer;
407 u32 mpeg_mode;
408 u32 mpeg_mode_extension;
409 u32 mpeg_pre_emphasis;
410 u32 mpeg_has_padding_bit;
411 u32 mpeg_has_crc;
412 u32 mpeg_has_extension;
413 u32 mpeg_is_original;
414 u32 mpeg_has_copyright;
415 } mpeg_format_info;
416 } format_info;
417
418 u32 delayed;
419 u64 scheduler;
420 u32 sample_size;
421 u32 has_header;
422 u32 has_suffix;
423 u32 has_bitrate;
424 u32 samples_per_frame;
425 u32 bytes_per_frame;
426 u32 bytes_per_sample;
427 u32 sampling_freq;
428 u32 number_of_channel;
429 u32 stream_number;
430 u32 buffer_size;
431 u32 differed_time;
432 u32 reserved4np[3];
433 u32 pipe_count; /* set to 1 (array size !) */
434 u32 stream_count; /* set to 1 (array size !) */
435 mixart_txx_stream_desc_t stream_desc[1]; /* only one stream per command, but this could be an array */
436
437} __attribute__((packed));
438
439
440/* MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL = 0x050009,
441 */
442
443
444typedef struct mixart_get_out_audio_level mixart_get_out_audio_level_t;
445struct mixart_get_out_audio_level
446{
447 u32 txx_status;
448 u32 digital_level; /* float */
449 u32 analog_level; /* float */
450 u32 monitor_level; /* float */
451 u32 mute;
452 u32 monitor_mute1;
453 u32 monitor_mute2;
454} __attribute__((packed));
455
456
457/* MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL = 0x05000A,
458 */
459
460/* used for valid_mask below */
461#define MIXART_AUDIO_LEVEL_ANALOG_MASK 0x01
462#define MIXART_AUDIO_LEVEL_DIGITAL_MASK 0x02
463#define MIXART_AUDIO_LEVEL_MONITOR_MASK 0x04
464#define MIXART_AUDIO_LEVEL_MUTE_MASK 0x08
465#define MIXART_AUDIO_LEVEL_MUTE_M1_MASK 0x10
466#define MIXART_AUDIO_LEVEL_MUTE_M2_MASK 0x20
467
468typedef struct mixart_set_out_audio_level mixart_set_out_audio_level_t;
469struct mixart_set_out_audio_level
470{
471 u32 delayed;
472 u64 scheduler;
473 u32 valid_mask1;
474 u32 valid_mask2;
475 u32 digital_level; /* float */
476 u32 analog_level; /* float */
477 u32 monitor_level; /* float */
478 u32 mute;
479 u32 monitor_mute1;
480 u32 monitor_mute2;
481 u32 reserved4np;
482} __attribute__((packed));
483
484
485/* MSG_SYSTEM_ENUM_PHYSICAL_IO = 0x16000E,
486 */
487
488#define MIXART_MAX_PHYS_IO (MIXART_MAX_CARDS * 2 * 2) /* 4 * (analog+digital) * (playback+capture) */
489
490typedef struct mixart_uid_enumeration mixart_uid_enumeration_t;
491struct mixart_uid_enumeration
492{
493 u32 error_code;
494 u32 first_uid_offset;
495 u32 nb_uid;
496 u32 current_uid_index;
497 mixart_uid_t uid[MIXART_MAX_PHYS_IO];
498} __attribute__((packed));
499
500
501/* MSG_PHYSICALIO_SET_LEVEL = 0x0F0008,
502 MSG_PHYSICALIO_GET_LEVEL = 0x0F000C,
503*/
504
505typedef struct mixart_io_channel_level mixart_io_channel_level_t;
506struct mixart_io_channel_level
507{
508 u32 analog_level; /* float */
509 u32 unused[2];
510} __attribute__((packed));
511
512typedef struct mixart_io_level mixart_io_level_t;
513struct mixart_io_level
514{
515 s32 channel; /* 0=left, 1=right, -1=both, -2=both same */
516 mixart_io_channel_level_t level[2];
517} __attribute__((packed));
518
519
520/* MSG_STREAM_SET_IN_AUDIO_LEVEL = 0x130015,
521 */
522
523typedef struct mixart_in_audio_level_info mixart_in_audio_level_info_t;
524struct mixart_in_audio_level_info
525{
526 mixart_uid_t connector;
527 u32 valid_mask1;
528 u32 valid_mask2;
529 u32 digital_level;
530 u32 analog_level;
531} __attribute__((packed));
532
533typedef struct mixart_set_in_audio_level_req mixart_set_in_audio_level_req_t;
534struct mixart_set_in_audio_level_req
535{
536 u32 delayed;
537 u64 scheduler;
538 u32 audio_count; /* set to <= 2 */
539 u32 reserved4np;
540 mixart_in_audio_level_info_t level[2];
541} __attribute__((packed));
542
543/* response is a 32 bit status */
544
545
546/* MSG_STREAM_SET_OUT_STREAM_LEVEL = 0x130017,
547 */
548
549/* defines used for valid_mask1 */
550#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1 0x01
551#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO2 0x02
552#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO1 0x04
553#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2 0x08
554#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_1 0x10
555#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_2 0x20
556#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_1 0x40
557#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_2 0x80
558
559typedef struct mixart_out_stream_level_info mixart_out_stream_level_info_t;
560struct mixart_out_stream_level_info
561{
562 u32 valid_mask1;
563 u32 valid_mask2;
564 u32 left_to_out1_level;
565 u32 left_to_out2_level;
566 u32 right_to_out1_level;
567 u32 right_to_out2_level;
568 u32 digital_level1;
569 u32 digital_level2;
570 u32 mute1;
571 u32 mute2;
572} __attribute__((packed));
573
574typedef struct mixart_set_out_stream_level mixart_set_out_stream_level_t;
575struct mixart_set_out_stream_level
576{
577 mixart_txx_stream_desc_t desc;
578 mixart_out_stream_level_info_t out_level;
579} __attribute__((packed));
580
581typedef struct mixart_set_out_stream_level_req mixart_set_out_stream_level_req_t;
582struct mixart_set_out_stream_level_req
583{
584 u32 delayed;
585 u64 scheduler;
586 u32 reserved4np[2];
587 u32 nb_of_stream; /* set to 1 */
588 mixart_set_out_stream_level_t stream_level; /* could be an array */
589} __attribute__((packed));
590
591/* response to this request is a u32 status value */
592
593
594/* exported */
595void snd_mixart_init_mailbox(mixart_mgr_t *mgr);
596void snd_mixart_exit_mailbox(mixart_mgr_t *mgr);
597
598int snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data);
599int snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event);
600int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request);
601
602irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs);
603void snd_mixart_msg_tasklet( unsigned long arg);
604
605void snd_mixart_reset_board(mixart_mgr_t *mgr);
606
607#endif /* __SOUND_MIXART_CORE_H */
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
new file mode 100644
index 000000000000..edd1599fe45e
--- /dev/null
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -0,0 +1,647 @@
1/*
2 * Driver for Digigram miXart soundcards
3 *
4 * DSP firmware management
5 *
6 * Copyright (c) 2003 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <sound/driver.h>
24#include <linux/interrupt.h>
25#include <linux/pci.h>
26#include <linux/firmware.h>
27#include <asm/io.h>
28#include <sound/core.h>
29#include "mixart.h"
30#include "mixart_mixer.h"
31#include "mixart_core.h"
32#include "mixart_hwdep.h"
33
34
35/**
36 * wait for a value on a peudo register, exit with a timeout
37 *
38 * @param mgr pointer to miXart manager structure
39 * @param offset unsigned pseudo_register base + offset of value
40 * @param value value
41 * @param timeout timeout in centisenconds
42 */
43static int mixart_wait_nice_for_register_value(mixart_mgr_t *mgr, u32 offset, int is_egal, u32 value, unsigned long timeout)
44{
45 unsigned long end_time = jiffies + (timeout * HZ / 100);
46 u32 read;
47
48 do { /* we may take too long time in this loop.
49 * so give controls back to kernel if needed.
50 */
51 cond_resched();
52
53 read = readl_be( MIXART_MEM( mgr, offset ));
54 if(is_egal) {
55 if(read == value) return 0;
56 }
57 else { /* wait for different value */
58 if(read != value) return 0;
59 }
60 } while ( time_after_eq(end_time, jiffies) );
61
62 return -EBUSY;
63}
64
65
66/*
67 structures needed to upload elf code packets
68 */
69typedef struct snd_mixart_elf32_ehdr snd_mixart_elf32_ehdr_t;
70
71struct snd_mixart_elf32_ehdr {
72 u8 e_ident[16];
73 u16 e_type;
74 u16 e_machine;
75 u32 e_version;
76 u32 e_entry;
77 u32 e_phoff;
78 u32 e_shoff;
79 u32 e_flags;
80 u16 e_ehsize;
81 u16 e_phentsize;
82 u16 e_phnum;
83 u16 e_shentsize;
84 u16 e_shnum;
85 u16 e_shstrndx;
86};
87
88typedef struct snd_mixart_elf32_phdr snd_mixart_elf32_phdr_t;
89
90struct snd_mixart_elf32_phdr {
91 u32 p_type;
92 u32 p_offset;
93 u32 p_vaddr;
94 u32 p_paddr;
95 u32 p_filesz;
96 u32 p_memsz;
97 u32 p_flags;
98 u32 p_align;
99};
100
101static int mixart_load_elf(mixart_mgr_t *mgr, const struct firmware *dsp )
102{
103 char elf32_magic_number[4] = {0x7f,'E','L','F'};
104 snd_mixart_elf32_ehdr_t *elf_header;
105 int i;
106
107 elf_header = (snd_mixart_elf32_ehdr_t *)dsp->data;
108 for( i=0; i<4; i++ )
109 if ( elf32_magic_number[i] != elf_header->e_ident[i] )
110 return -EINVAL;
111
112 if( elf_header->e_phoff != 0 ) {
113 snd_mixart_elf32_phdr_t elf_programheader;
114
115 for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {
116 u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));
117
118 memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );
119
120 if(elf_programheader.p_type != 0) {
121 if( elf_programheader.p_filesz != 0 ) {
122 memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
123 dsp->data + be32_to_cpu( elf_programheader.p_offset ),
124 be32_to_cpu( elf_programheader.p_filesz ));
125 }
126 }
127 }
128 }
129 return 0;
130}
131
132/*
133 * get basic information and init miXart
134 */
135
136/* audio IDs for request to the board */
137#define MIXART_FIRST_ANA_AUDIO_ID 0
138#define MIXART_FIRST_DIG_AUDIO_ID 8
139
140static int mixart_enum_connectors(mixart_mgr_t *mgr)
141{
142 u32 k;
143 int err;
144 mixart_msg_t request;
145 mixart_enum_connector_resp_t *connector;
146 mixart_audio_info_req_t *audio_info_req;
147 mixart_audio_info_resp_t *audio_info;
148
149 connector = kmalloc(sizeof(*connector), GFP_KERNEL);
150 audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);
151 audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);
152 if (! connector || ! audio_info_req || ! audio_info) {
153 err = -ENOMEM;
154 goto __error;
155 }
156
157 audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
158 audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
159 audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
160
161 request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
162 request.uid = (mixart_uid_t){0,0}; /* board num = 0 */
163 request.data = NULL;
164 request.size = 0;
165
166 err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
167 if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
168 snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
169 err = -EINVAL;
170 goto __error;
171 }
172
173 for(k=0; k < connector->uid_count; k++) {
174 mixart_pipe_t* pipe;
175
176 if(k < MIXART_FIRST_DIG_AUDIO_ID) {
177 pipe = &mgr->chip[k/2]->pipe_out_ana;
178 } else {
179 pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
180 }
181 if(k & 1) {
182 pipe->uid_right_connector = connector->uid[k]; /* odd */
183 } else {
184 pipe->uid_left_connector = connector->uid[k]; /* even */
185 }
186
187 /* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
188
189 /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
190 request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
191 request.uid = connector->uid[k];
192 request.data = audio_info_req;
193 request.size = sizeof(*audio_info_req);
194
195 err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
196 if( err < 0 ) {
197 snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
198 goto __error;
199 }
200 /*snd_printk(KERN_DEBUG "play analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
201 }
202
203 request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
204 request.uid = (mixart_uid_t){0,0}; /* board num = 0 */
205 request.data = NULL;
206 request.size = 0;
207
208 err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
209 if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
210 snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
211 err = -EINVAL;
212 goto __error;
213 }
214
215 for(k=0; k < connector->uid_count; k++) {
216 mixart_pipe_t* pipe;
217
218 if(k < MIXART_FIRST_DIG_AUDIO_ID) {
219 pipe = &mgr->chip[k/2]->pipe_in_ana;
220 } else {
221 pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
222 }
223 if(k & 1) {
224 pipe->uid_right_connector = connector->uid[k]; /* odd */
225 } else {
226 pipe->uid_left_connector = connector->uid[k]; /* even */
227 }
228
229 /* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
230
231 /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
232 request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
233 request.uid = connector->uid[k];
234 request.data = audio_info_req;
235 request.size = sizeof(*audio_info_req);
236
237 err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
238 if( err < 0 ) {
239 snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
240 goto __error;
241 }
242 /*snd_printk(KERN_DEBUG "rec analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
243 }
244 err = 0;
245
246 __error:
247 kfree(connector);
248 kfree(audio_info_req);
249 kfree(audio_info);
250
251 return err;
252}
253
254static int mixart_enum_physio(mixart_mgr_t *mgr)
255{
256 u32 k;
257 int err;
258 mixart_msg_t request;
259 mixart_uid_t get_console_mgr;
260 mixart_return_uid_t console_mgr;
261 mixart_uid_enumeration_t phys_io;
262
263 /* get the uid for the console manager */
264 get_console_mgr.object_id = 0;
265 get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */
266
267 request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
268 request.uid = get_console_mgr;
269 request.data = &get_console_mgr;
270 request.size = sizeof(get_console_mgr);
271
272 err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
273
274 if( (err < 0) || (console_mgr.error_code != 0) ) {
275 snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code);
276 return -EINVAL;
277 }
278
279 /* used later for clock issues ! */
280 mgr->uid_console_manager = console_mgr.uid;
281
282 request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
283 request.uid = (mixart_uid_t){0,0};
284 request.data = &console_mgr.uid;
285 request.size = sizeof(console_mgr.uid);
286
287 err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
288 if( (err < 0) || ( phys_io.error_code != 0 ) ) {
289 snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code );
290 return -EINVAL;
291 }
292
293 snd_assert(phys_io.nb_uid >= (MIXART_MAX_CARDS * 2), return -EINVAL); /* min 2 phys io per card (analog in + analog out) */
294
295 for(k=0; k<mgr->num_cards; k++) {
296 mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
297 mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k];
298 }
299
300 return 0;
301}
302
303
304static int mixart_first_init(mixart_mgr_t *mgr)
305{
306 u32 k;
307 int err;
308 mixart_msg_t request;
309
310 if((err = mixart_enum_connectors(mgr)) < 0) return err;
311
312 if((err = mixart_enum_physio(mgr)) < 0) return err;
313
314 /* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */
315 /* though why not here */
316 request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
317 request.uid = (mixart_uid_t){0,0};
318 request.data = NULL;
319 request.size = 0;
320 /* this command has no data. response is a 32 bit status */
321 err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
322 if( (err < 0) || (k != 0) ) {
323 snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
324 return err == 0 ? -EINVAL : err;
325 }
326
327 return 0;
328}
329
330
331/* firmware base addresses (when hard coded) */
332#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS 0x00600000
333
334static int mixart_dsp_load(mixart_mgr_t* mgr, int index, const struct firmware *dsp)
335{
336 int err, card_index;
337 u32 status_xilinx, status_elf, status_daught;
338 u32 val;
339
340 /* read motherboard xilinx status */
341 status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
342 /* read elf status */
343 status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
344 /* read daughterboard xilinx status */
345 status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
346
347 /* motherboard xilinx status 5 will say that the board is performing a reset */
348 if( status_xilinx == 5 ) {
349 snd_printk( KERN_ERR "miXart is resetting !\n");
350 return -EAGAIN; /* try again later */
351 }
352
353 switch (index) {
354 case MIXART_MOTHERBOARD_XLX_INDEX:
355
356 /* xilinx already loaded ? */
357 if( status_xilinx == 4 ) {
358 snd_printk( KERN_DEBUG "xilinx is already loaded !\n");
359 return 0;
360 }
361 /* the status should be 0 == "idle" */
362 if( status_xilinx != 0 ) {
363 snd_printk( KERN_ERR "xilinx load error ! status = %d\n", status_xilinx);
364 return -EIO; /* modprob -r may help ? */
365 }
366
367 /* check xilinx validity */
368 snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
369 snd_assert(dsp->size % 4 == 0, return -EINVAL);
370
371 /* set xilinx status to copying */
372 writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
373
374 /* setup xilinx base address */
375 writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
376 /* setup code size for xilinx file */
377 writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
378
379 /* copy xilinx code */
380 memcpy_toio( MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS), dsp->data, dsp->size);
381
382 /* set xilinx status to copy finished */
383 writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
384
385 /* return, because no further processing needed */
386 return 0;
387
388 case MIXART_MOTHERBOARD_ELF_INDEX:
389
390 if( status_elf == 4 ) {
391 snd_printk( KERN_DEBUG "elf file already loaded !\n");
392 return 0;
393 }
394
395 /* the status should be 0 == "idle" */
396 if( status_elf != 0 ) {
397 snd_printk( KERN_ERR "elf load error ! status = %d\n", status_elf);
398 return -EIO; /* modprob -r may help ? */
399 }
400
401 /* wait for xilinx status == 4 */
402 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
403 if (err < 0) {
404 snd_printk( KERN_ERR "xilinx was not loaded or could not be started\n");
405 return err;
406 }
407
408 /* init some data on the card */
409 writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */
410 writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* reset pointer to flow table on miXart */
411
412 /* set elf status to copying */
413 writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
414
415 /* process the copying of the elf packets */
416 err = mixart_load_elf( mgr, dsp );
417 if (err < 0) return err;
418
419 /* set elf status to copy finished */
420 writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
421
422 /* wait for elf status == 4 */
423 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
424 if (err < 0) {
425 snd_printk( KERN_ERR "elf could not be started\n");
426 return err;
427 }
428
429 /* miXart waits at this point on the pointer to the flow table */
430 writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */
431
432 return 0; /* return, another xilinx file has to be loaded before */
433
434 case MIXART_AESEBUBOARD_XLX_INDEX:
435 default:
436
437 /* elf and xilinx should be loaded */
438 if( (status_elf != 4) || (status_xilinx != 4) ) {
439 printk( KERN_ERR "xilinx or elf not successfully loaded\n");
440 return -EIO; /* modprob -r may help ? */
441 }
442
443 /* wait for daughter detection != 0 */
444 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
445 if (err < 0) {
446 snd_printk( KERN_ERR "error starting elf file\n");
447 return err;
448 }
449
450 /* the board type can now be retrieved */
451 mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
452
453 if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
454 break; /* no daughter board; the file does not have to be loaded, continue after the switch */
455
456 /* only if aesebu daughter board presence (elf code must run) */
457 if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
458 return -EINVAL;
459
460 /* daughter should be idle */
461 if( status_daught != 0 ) {
462 printk( KERN_ERR "daughter load error ! status = %d\n", status_daught);
463 return -EIO; /* modprob -r may help ? */
464 }
465
466 /* check daughterboard xilinx validity */
467 snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
468 snd_assert(dsp->size % 4 == 0, return -EINVAL);
469
470 /* inform mixart about the size of the file */
471 writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
472
473 /* set daughterboard status to 1 */
474 writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
475
476 /* wait for status == 2 */
477 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
478 if (err < 0) {
479 snd_printk( KERN_ERR "daughter board load error\n");
480 return err;
481 }
482
483 /* get the address where to write the file */
484 val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
485 snd_assert(val != 0, return -EINVAL);
486
487 /* copy daughterboard xilinx code */
488 memcpy_toio( MIXART_MEM( mgr, val), dsp->data, dsp->size);
489
490 /* set daughterboard status to 4 */
491 writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
492
493 /* continue with init */
494 break;
495 } /* end of switch file index*/
496
497 /* wait for daughter status == 3 */
498 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
499 if (err < 0) {
500 snd_printk( KERN_ERR "daughter board could not be initialised\n");
501 return err;
502 }
503
504 /* init mailbox (communication with embedded) */
505 snd_mixart_init_mailbox(mgr);
506
507 /* first communication with embedded */
508 err = mixart_first_init(mgr);
509 if (err < 0) {
510 snd_printk( KERN_ERR "miXart could not be set up\n");
511 return err;
512 }
513
514 /* create devices and mixer in accordance with HW options*/
515 for (card_index = 0; card_index < mgr->num_cards; card_index++) {
516 mixart_t *chip = mgr->chip[card_index];
517
518 if ((err = snd_mixart_create_pcm(chip)) < 0)
519 return err;
520
521 if (card_index == 0) {
522 if ((err = snd_mixart_create_mixer(chip->mgr)) < 0)
523 return err;
524 }
525
526 if ((err = snd_card_register(chip->card)) < 0)
527 return err;
528 };
529
530 snd_printdd("miXart firmware downloaded and successfully set up\n");
531
532 return 0;
533}
534
535
536#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
537#if !defined(CONFIG_USE_MIXARTLOADER) && !defined(CONFIG_SND_MIXART) /* built-in kernel */
538#define SND_MIXART_FW_LOADER /* use the standard firmware loader */
539#endif
540#endif
541
542#ifdef SND_MIXART_FW_LOADER
543
544int snd_mixart_setup_firmware(mixart_mgr_t *mgr)
545{
546 static char *fw_files[3] = {
547 "miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
548 };
549 char path[32];
550
551 const struct firmware *fw_entry;
552 int i, err;
553
554 for (i = 0; i < 3; i++) {
555 sprintf(path, "mixart/%s", fw_files[i]);
556 if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
557 snd_printk(KERN_ERR "miXart: can't load firmware %s\n", path);
558 return -ENOENT;
559 }
560 /* fake hwdep dsp record */
561 err = mixart_dsp_load(mgr, i, fw_entry);
562 release_firmware(fw_entry);
563 if (err < 0)
564 return err;
565 mgr->dsp_loaded |= 1 << i;
566 }
567 return 0;
568}
569
570
571#else /* old style firmware loading */
572
573/* miXart hwdep interface id string */
574#define SND_MIXART_HWDEP_ID "miXart Loader"
575
576static int mixart_hwdep_open(snd_hwdep_t *hw, struct file *file)
577{
578 return 0;
579}
580
581static int mixart_hwdep_release(snd_hwdep_t *hw, struct file *file)
582{
583 return 0;
584}
585
586static int mixart_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
587{
588 mixart_mgr_t *mgr = hw->private_data;
589
590 strcpy(info->id, "miXart");
591 info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX;
592
593 if (mgr->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX))
594 info->chip_ready = 1;
595
596 info->version = MIXART_DRIVER_VERSION;
597 return 0;
598}
599
600static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
601{
602 mixart_mgr_t* mgr = hw->private_data;
603 struct firmware fw;
604 int err;
605
606 fw.size = dsp->length;
607 fw.data = vmalloc(dsp->length);
608 if (! fw.data) {
609 snd_printk(KERN_ERR "miXart: cannot allocate image size %d\n",
610 (int)dsp->length);
611 return -ENOMEM;
612 }
613 if (copy_from_user(fw.data, dsp->image, dsp->length)) {
614 vfree(fw.data);
615 return -EFAULT;
616 }
617 err = mixart_dsp_load(mgr, dsp->index, &fw);
618 vfree(fw.data);
619 if (err < 0)
620 return err;
621 mgr->dsp_loaded |= 1 << dsp->index;
622 return err;
623}
624
625int snd_mixart_setup_firmware(mixart_mgr_t *mgr)
626{
627 int err;
628 snd_hwdep_t *hw;
629
630 /* only create hwdep interface for first cardX (see "index" module parameter)*/
631 if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0)
632 return err;
633
634 hw->iface = SNDRV_HWDEP_IFACE_MIXART;
635 hw->private_data = mgr;
636 hw->ops.open = mixart_hwdep_open;
637 hw->ops.release = mixart_hwdep_release;
638 hw->ops.dsp_status = mixart_hwdep_dsp_status;
639 hw->ops.dsp_load = mixart_hwdep_dsp_load;
640 hw->exclusive = 1;
641 sprintf(hw->name, SND_MIXART_HWDEP_ID);
642 mgr->dsp_loaded = 0;
643
644 return snd_card_register(mgr->chip[0]->card);
645}
646
647#endif /* SND_MIXART_FW_LOADER */
diff --git a/sound/pci/mixart/mixart_hwdep.h b/sound/pci/mixart/mixart_hwdep.h
new file mode 100644
index 000000000000..25190cc88cf8
--- /dev/null
+++ b/sound/pci/mixart/mixart_hwdep.h
@@ -0,0 +1,145 @@
1/*
2 * Driver for Digigram miXart soundcards
3 *
4 * definitions and makros for basic card access
5 *
6 * Copyright (c) 2003 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef __SOUND_MIXART_HWDEP_H
24#define __SOUND_MIXART_HWDEP_H
25
26#include <sound/hwdep.h>
27
28#define readl_be(x) be32_to_cpu(__raw_readl(x))
29#define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr)
30
31#define readl_le(x) le32_to_cpu(__raw_readl(x))
32#define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr)
33
34#define MIXART_MEM(mgr,x) ((mgr)->mem[0].virt + (x))
35#define MIXART_REG(mgr,x) ((mgr)->mem[1].virt + (x))
36
37
38/* Daughter board Type */
39#define DAUGHTER_TYPE_MASK 0x0F
40#define DAUGHTER_VER_MASK 0xF0
41#define DAUGHTER_TYPEVER_MASK (DAUGHTER_TYPE_MASK|DAUGHTER_VER_MASK)
42
43#define MIXART_DAUGHTER_TYPE_NONE 0x00
44#define MIXART_DAUGHTER_TYPE_COBRANET 0x08
45#define MIXART_DAUGHTER_TYPE_AES 0x0E
46
47
48
49#define MIXART_BA0_SIZE (16 * 1024 * 1024) /* 16M */
50#define MIXART_BA1_SIZE (4 * 1024) /* 4k */
51
52/*
53 * -----------BAR 0 --------------------------------------------------------------------------------------------------------
54 */
55#define MIXART_PSEUDOREG 0x2000 /* base address for pseudoregister */
56
57#define MIXART_PSEUDOREG_BOARDNUMBER MIXART_PSEUDOREG+0 /* board number */
58
59/* perfmeter (available when elf loaded)*/
60#define MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET MIXART_PSEUDOREG+0x70 /* streaming load */
61#define MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET MIXART_PSEUDOREG+0x78 /* system load (reference)*/
62#define MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET MIXART_PSEUDOREG+0x7C /* mailbox load */
63#define MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET MIXART_PSEUDOREG+0x74 /* interrupt handling load */
64
65/* motherboard xilinx loader info */
66#define MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET MIXART_PSEUDOREG+0x9C /* 0x00600000 */
67#define MIXART_PSEUDOREG_MXLX_SIZE_OFFSET MIXART_PSEUDOREG+0xA0 /* xilinx size in bytes */
68#define MIXART_PSEUDOREG_MXLX_STATUS_OFFSET MIXART_PSEUDOREG+0xA4 /* status = EMBEBBED_STAT_XXX */
69
70/* elf loader info */
71#define MIXART_PSEUDOREG_ELF_STATUS_OFFSET MIXART_PSEUDOREG+0xB0 /* status = EMBEBBED_STAT_XXX */
72
73/*
74* after the elf code is loaded, and the flowtable info was passed to it,
75* the driver polls on this address, until it shows 1 (presence) or 2 (absence)
76* once it is non-zero, the daughter board type may be read
77*/
78#define MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET MIXART_PSEUDOREG+0x990
79
80/* Global info structure */
81#define MIXART_PSEUDOREG_DBRD_TYPE_OFFSET MIXART_PSEUDOREG+0x994 /* Type and version of daughterboard */
82
83
84/* daughterboard xilinx loader info */
85#define MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET MIXART_PSEUDOREG+0x998 /* get the address here where to write the file */
86#define MIXART_PSEUDOREG_DXLX_SIZE_OFFSET MIXART_PSEUDOREG+0x99C /* xilinx size in bytes */
87#define MIXART_PSEUDOREG_DXLX_STATUS_OFFSET MIXART_PSEUDOREG+0x9A0 /* status = EMBEBBED_STAT_XXX */
88
89/* */
90#define MIXART_FLOWTABLE_PTR 0x3000 /* pointer to flow table */
91
92/* mailbox addresses */
93
94/* message DRV -> EMB */
95#define MSG_INBOUND_POST_HEAD 0x010008 /* DRV posts MF + increment4 */
96#define MSG_INBOUND_POST_TAIL 0x01000C /* EMB gets MF + increment4 */
97/* message EMB -> DRV */
98#define MSG_OUTBOUND_POST_TAIL 0x01001C /* DRV gets MF + increment4 */
99#define MSG_OUTBOUND_POST_HEAD 0x010018 /* EMB posts MF + increment4 */
100/* Get Free Frames */
101#define MSG_INBOUND_FREE_TAIL 0x010004 /* DRV gets MFA + increment4 */
102#define MSG_OUTBOUND_FREE_TAIL 0x010014 /* EMB gets MFA + increment4 */
103/* Put Free Frames */
104#define MSG_OUTBOUND_FREE_HEAD 0x010010 /* DRV puts MFA + increment4 */
105#define MSG_INBOUND_FREE_HEAD 0x010000 /* EMB puts MFA + increment4 */
106
107/* firmware addresses of the message fifos */
108#define MSG_BOUND_STACK_SIZE 0x004000 /* size of each following stack */
109/* posted messages */
110#define MSG_OUTBOUND_POST_STACK 0x108000 /* stack of messages to the DRV */
111#define MSG_INBOUND_POST_STACK 0x104000 /* stack of messages to the EMB */
112/* available empty messages */
113#define MSG_OUTBOUND_FREE_STACK 0x10C000 /* stack of free enveloped for EMB */
114#define MSG_INBOUND_FREE_STACK 0x100000 /* stack of free enveloped for DRV */
115
116
117/* defines for mailbox message frames */
118#define MSG_FRAME_OFFSET 0x64
119#define MSG_FRAME_SIZE 0x6400
120#define MSG_FRAME_NUMBER 32
121#define MSG_FROM_AGENT_ITMF_OFFSET (MSG_FRAME_OFFSET + (MSG_FRAME_SIZE * MSG_FRAME_NUMBER))
122#define MSG_TO_AGENT_ITMF_OFFSET (MSG_FROM_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
123#define MSG_HOST_RSC_PROTECTION (MSG_TO_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
124#define MSG_AGENT_RSC_PROTECTION (MSG_HOST_RSC_PROTECTION + 4)
125
126
127/*
128 * -----------BAR 1 --------------------------------------------------------------------------------------------------------
129 */
130
131/* interrupt addresses and constants */
132#define MIXART_PCI_OMIMR_OFFSET 0x34 /* outbound message interrupt mask register */
133#define MIXART_PCI_OMISR_OFFSET 0x30 /* outbound message interrupt status register */
134#define MIXART_PCI_ODBR_OFFSET 0x60 /* outbound doorbell register */
135
136#define MIXART_BA1_BRUTAL_RESET_OFFSET 0x68 /* write 1 in LSBit to reset board */
137
138#define MIXART_HOST_ALL_INTERRUPT_MASKED 0x02B /* 0000 0010 1011 */
139#define MIXART_ALLOW_OUTBOUND_DOORBELL 0x023 /* 0000 0010 0011 */
140#define MIXART_OIDI 0x008 /* 0000 0000 1000 */
141
142
143int snd_mixart_setup_firmware(mixart_mgr_t *mgr);
144
145#endif /* __SOUND_MIXART_HWDEP_H */
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
new file mode 100644
index 000000000000..39c15416fc80
--- /dev/null
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -0,0 +1,1136 @@
1/*
2 * Driver for Digigram miXart soundcards
3 *
4 * mixer callbacks
5 *
6 * Copyright (c) 2003 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <sound/driver.h>
24#include <linux/time.h>
25#include <linux/interrupt.h>
26#include <linux/init.h>
27#include <sound/core.h>
28#include "mixart.h"
29#include "mixart_core.h"
30#include "mixart_hwdep.h"
31#include <sound/control.h>
32#include "mixart_mixer.h"
33
34static u32 mixart_analog_level[256] = {
35 0xc2c00000, /* [000] -96.0 dB */
36 0xc2bf0000, /* [001] -95.5 dB */
37 0xc2be0000, /* [002] -95.0 dB */
38 0xc2bd0000, /* [003] -94.5 dB */
39 0xc2bc0000, /* [004] -94.0 dB */
40 0xc2bb0000, /* [005] -93.5 dB */
41 0xc2ba0000, /* [006] -93.0 dB */
42 0xc2b90000, /* [007] -92.5 dB */
43 0xc2b80000, /* [008] -92.0 dB */
44 0xc2b70000, /* [009] -91.5 dB */
45 0xc2b60000, /* [010] -91.0 dB */
46 0xc2b50000, /* [011] -90.5 dB */
47 0xc2b40000, /* [012] -90.0 dB */
48 0xc2b30000, /* [013] -89.5 dB */
49 0xc2b20000, /* [014] -89.0 dB */
50 0xc2b10000, /* [015] -88.5 dB */
51 0xc2b00000, /* [016] -88.0 dB */
52 0xc2af0000, /* [017] -87.5 dB */
53 0xc2ae0000, /* [018] -87.0 dB */
54 0xc2ad0000, /* [019] -86.5 dB */
55 0xc2ac0000, /* [020] -86.0 dB */
56 0xc2ab0000, /* [021] -85.5 dB */
57 0xc2aa0000, /* [022] -85.0 dB */
58 0xc2a90000, /* [023] -84.5 dB */
59 0xc2a80000, /* [024] -84.0 dB */
60 0xc2a70000, /* [025] -83.5 dB */
61 0xc2a60000, /* [026] -83.0 dB */
62 0xc2a50000, /* [027] -82.5 dB */
63 0xc2a40000, /* [028] -82.0 dB */
64 0xc2a30000, /* [029] -81.5 dB */
65 0xc2a20000, /* [030] -81.0 dB */
66 0xc2a10000, /* [031] -80.5 dB */
67 0xc2a00000, /* [032] -80.0 dB */
68 0xc29f0000, /* [033] -79.5 dB */
69 0xc29e0000, /* [034] -79.0 dB */
70 0xc29d0000, /* [035] -78.5 dB */
71 0xc29c0000, /* [036] -78.0 dB */
72 0xc29b0000, /* [037] -77.5 dB */
73 0xc29a0000, /* [038] -77.0 dB */
74 0xc2990000, /* [039] -76.5 dB */
75 0xc2980000, /* [040] -76.0 dB */
76 0xc2970000, /* [041] -75.5 dB */
77 0xc2960000, /* [042] -75.0 dB */
78 0xc2950000, /* [043] -74.5 dB */
79 0xc2940000, /* [044] -74.0 dB */
80 0xc2930000, /* [045] -73.5 dB */
81 0xc2920000, /* [046] -73.0 dB */
82 0xc2910000, /* [047] -72.5 dB */
83 0xc2900000, /* [048] -72.0 dB */
84 0xc28f0000, /* [049] -71.5 dB */
85 0xc28e0000, /* [050] -71.0 dB */
86 0xc28d0000, /* [051] -70.5 dB */
87 0xc28c0000, /* [052] -70.0 dB */
88 0xc28b0000, /* [053] -69.5 dB */
89 0xc28a0000, /* [054] -69.0 dB */
90 0xc2890000, /* [055] -68.5 dB */
91 0xc2880000, /* [056] -68.0 dB */
92 0xc2870000, /* [057] -67.5 dB */
93 0xc2860000, /* [058] -67.0 dB */
94 0xc2850000, /* [059] -66.5 dB */
95 0xc2840000, /* [060] -66.0 dB */
96 0xc2830000, /* [061] -65.5 dB */
97 0xc2820000, /* [062] -65.0 dB */
98 0xc2810000, /* [063] -64.5 dB */
99 0xc2800000, /* [064] -64.0 dB */
100 0xc27e0000, /* [065] -63.5 dB */
101 0xc27c0000, /* [066] -63.0 dB */
102 0xc27a0000, /* [067] -62.5 dB */
103 0xc2780000, /* [068] -62.0 dB */
104 0xc2760000, /* [069] -61.5 dB */
105 0xc2740000, /* [070] -61.0 dB */
106 0xc2720000, /* [071] -60.5 dB */
107 0xc2700000, /* [072] -60.0 dB */
108 0xc26e0000, /* [073] -59.5 dB */
109 0xc26c0000, /* [074] -59.0 dB */
110 0xc26a0000, /* [075] -58.5 dB */
111 0xc2680000, /* [076] -58.0 dB */
112 0xc2660000, /* [077] -57.5 dB */
113 0xc2640000, /* [078] -57.0 dB */
114 0xc2620000, /* [079] -56.5 dB */
115 0xc2600000, /* [080] -56.0 dB */
116 0xc25e0000, /* [081] -55.5 dB */
117 0xc25c0000, /* [082] -55.0 dB */
118 0xc25a0000, /* [083] -54.5 dB */
119 0xc2580000, /* [084] -54.0 dB */
120 0xc2560000, /* [085] -53.5 dB */
121 0xc2540000, /* [086] -53.0 dB */
122 0xc2520000, /* [087] -52.5 dB */
123 0xc2500000, /* [088] -52.0 dB */
124 0xc24e0000, /* [089] -51.5 dB */
125 0xc24c0000, /* [090] -51.0 dB */
126 0xc24a0000, /* [091] -50.5 dB */
127 0xc2480000, /* [092] -50.0 dB */
128 0xc2460000, /* [093] -49.5 dB */
129 0xc2440000, /* [094] -49.0 dB */
130 0xc2420000, /* [095] -48.5 dB */
131 0xc2400000, /* [096] -48.0 dB */
132 0xc23e0000, /* [097] -47.5 dB */
133 0xc23c0000, /* [098] -47.0 dB */
134 0xc23a0000, /* [099] -46.5 dB */
135 0xc2380000, /* [100] -46.0 dB */
136 0xc2360000, /* [101] -45.5 dB */
137 0xc2340000, /* [102] -45.0 dB */
138 0xc2320000, /* [103] -44.5 dB */
139 0xc2300000, /* [104] -44.0 dB */
140 0xc22e0000, /* [105] -43.5 dB */
141 0xc22c0000, /* [106] -43.0 dB */
142 0xc22a0000, /* [107] -42.5 dB */
143 0xc2280000, /* [108] -42.0 dB */
144 0xc2260000, /* [109] -41.5 dB */
145 0xc2240000, /* [110] -41.0 dB */
146 0xc2220000, /* [111] -40.5 dB */
147 0xc2200000, /* [112] -40.0 dB */
148 0xc21e0000, /* [113] -39.5 dB */
149 0xc21c0000, /* [114] -39.0 dB */
150 0xc21a0000, /* [115] -38.5 dB */
151 0xc2180000, /* [116] -38.0 dB */
152 0xc2160000, /* [117] -37.5 dB */
153 0xc2140000, /* [118] -37.0 dB */
154 0xc2120000, /* [119] -36.5 dB */
155 0xc2100000, /* [120] -36.0 dB */
156 0xc20e0000, /* [121] -35.5 dB */
157 0xc20c0000, /* [122] -35.0 dB */
158 0xc20a0000, /* [123] -34.5 dB */
159 0xc2080000, /* [124] -34.0 dB */
160 0xc2060000, /* [125] -33.5 dB */
161 0xc2040000, /* [126] -33.0 dB */
162 0xc2020000, /* [127] -32.5 dB */
163 0xc2000000, /* [128] -32.0 dB */
164 0xc1fc0000, /* [129] -31.5 dB */
165 0xc1f80000, /* [130] -31.0 dB */
166 0xc1f40000, /* [131] -30.5 dB */
167 0xc1f00000, /* [132] -30.0 dB */
168 0xc1ec0000, /* [133] -29.5 dB */
169 0xc1e80000, /* [134] -29.0 dB */
170 0xc1e40000, /* [135] -28.5 dB */
171 0xc1e00000, /* [136] -28.0 dB */
172 0xc1dc0000, /* [137] -27.5 dB */
173 0xc1d80000, /* [138] -27.0 dB */
174 0xc1d40000, /* [139] -26.5 dB */
175 0xc1d00000, /* [140] -26.0 dB */
176 0xc1cc0000, /* [141] -25.5 dB */
177 0xc1c80000, /* [142] -25.0 dB */
178 0xc1c40000, /* [143] -24.5 dB */
179 0xc1c00000, /* [144] -24.0 dB */
180 0xc1bc0000, /* [145] -23.5 dB */
181 0xc1b80000, /* [146] -23.0 dB */
182 0xc1b40000, /* [147] -22.5 dB */
183 0xc1b00000, /* [148] -22.0 dB */
184 0xc1ac0000, /* [149] -21.5 dB */
185 0xc1a80000, /* [150] -21.0 dB */
186 0xc1a40000, /* [151] -20.5 dB */
187 0xc1a00000, /* [152] -20.0 dB */
188 0xc19c0000, /* [153] -19.5 dB */
189 0xc1980000, /* [154] -19.0 dB */
190 0xc1940000, /* [155] -18.5 dB */
191 0xc1900000, /* [156] -18.0 dB */
192 0xc18c0000, /* [157] -17.5 dB */
193 0xc1880000, /* [158] -17.0 dB */
194 0xc1840000, /* [159] -16.5 dB */
195 0xc1800000, /* [160] -16.0 dB */
196 0xc1780000, /* [161] -15.5 dB */
197 0xc1700000, /* [162] -15.0 dB */
198 0xc1680000, /* [163] -14.5 dB */
199 0xc1600000, /* [164] -14.0 dB */
200 0xc1580000, /* [165] -13.5 dB */
201 0xc1500000, /* [166] -13.0 dB */
202 0xc1480000, /* [167] -12.5 dB */
203 0xc1400000, /* [168] -12.0 dB */
204 0xc1380000, /* [169] -11.5 dB */
205 0xc1300000, /* [170] -11.0 dB */
206 0xc1280000, /* [171] -10.5 dB */
207 0xc1200000, /* [172] -10.0 dB */
208 0xc1180000, /* [173] -9.5 dB */
209 0xc1100000, /* [174] -9.0 dB */
210 0xc1080000, /* [175] -8.5 dB */
211 0xc1000000, /* [176] -8.0 dB */
212 0xc0f00000, /* [177] -7.5 dB */
213 0xc0e00000, /* [178] -7.0 dB */
214 0xc0d00000, /* [179] -6.5 dB */
215 0xc0c00000, /* [180] -6.0 dB */
216 0xc0b00000, /* [181] -5.5 dB */
217 0xc0a00000, /* [182] -5.0 dB */
218 0xc0900000, /* [183] -4.5 dB */
219 0xc0800000, /* [184] -4.0 dB */
220 0xc0600000, /* [185] -3.5 dB */
221 0xc0400000, /* [186] -3.0 dB */
222 0xc0200000, /* [187] -2.5 dB */
223 0xc0000000, /* [188] -2.0 dB */
224 0xbfc00000, /* [189] -1.5 dB */
225 0xbf800000, /* [190] -1.0 dB */
226 0xbf000000, /* [191] -0.5 dB */
227 0x00000000, /* [192] 0.0 dB */
228 0x3f000000, /* [193] 0.5 dB */
229 0x3f800000, /* [194] 1.0 dB */
230 0x3fc00000, /* [195] 1.5 dB */
231 0x40000000, /* [196] 2.0 dB */
232 0x40200000, /* [197] 2.5 dB */
233 0x40400000, /* [198] 3.0 dB */
234 0x40600000, /* [199] 3.5 dB */
235 0x40800000, /* [200] 4.0 dB */
236 0x40900000, /* [201] 4.5 dB */
237 0x40a00000, /* [202] 5.0 dB */
238 0x40b00000, /* [203] 5.5 dB */
239 0x40c00000, /* [204] 6.0 dB */
240 0x40d00000, /* [205] 6.5 dB */
241 0x40e00000, /* [206] 7.0 dB */
242 0x40f00000, /* [207] 7.5 dB */
243 0x41000000, /* [208] 8.0 dB */
244 0x41080000, /* [209] 8.5 dB */
245 0x41100000, /* [210] 9.0 dB */
246 0x41180000, /* [211] 9.5 dB */
247 0x41200000, /* [212] 10.0 dB */
248 0x41280000, /* [213] 10.5 dB */
249 0x41300000, /* [214] 11.0 dB */
250 0x41380000, /* [215] 11.5 dB */
251 0x41400000, /* [216] 12.0 dB */
252 0x41480000, /* [217] 12.5 dB */
253 0x41500000, /* [218] 13.0 dB */
254 0x41580000, /* [219] 13.5 dB */
255 0x41600000, /* [220] 14.0 dB */
256 0x41680000, /* [221] 14.5 dB */
257 0x41700000, /* [222] 15.0 dB */
258 0x41780000, /* [223] 15.5 dB */
259 0x41800000, /* [224] 16.0 dB */
260 0x41840000, /* [225] 16.5 dB */
261 0x41880000, /* [226] 17.0 dB */
262 0x418c0000, /* [227] 17.5 dB */
263 0x41900000, /* [228] 18.0 dB */
264 0x41940000, /* [229] 18.5 dB */
265 0x41980000, /* [230] 19.0 dB */
266 0x419c0000, /* [231] 19.5 dB */
267 0x41a00000, /* [232] 20.0 dB */
268 0x41a40000, /* [233] 20.5 dB */
269 0x41a80000, /* [234] 21.0 dB */
270 0x41ac0000, /* [235] 21.5 dB */
271 0x41b00000, /* [236] 22.0 dB */
272 0x41b40000, /* [237] 22.5 dB */
273 0x41b80000, /* [238] 23.0 dB */
274 0x41bc0000, /* [239] 23.5 dB */
275 0x41c00000, /* [240] 24.0 dB */
276 0x41c40000, /* [241] 24.5 dB */
277 0x41c80000, /* [242] 25.0 dB */
278 0x41cc0000, /* [243] 25.5 dB */
279 0x41d00000, /* [244] 26.0 dB */
280 0x41d40000, /* [245] 26.5 dB */
281 0x41d80000, /* [246] 27.0 dB */
282 0x41dc0000, /* [247] 27.5 dB */
283 0x41e00000, /* [248] 28.0 dB */
284 0x41e40000, /* [249] 28.5 dB */
285 0x41e80000, /* [250] 29.0 dB */
286 0x41ec0000, /* [251] 29.5 dB */
287 0x41f00000, /* [252] 30.0 dB */
288 0x41f40000, /* [253] 30.5 dB */
289 0x41f80000, /* [254] 31.0 dB */
290 0x41fc0000, /* [255] 31.5 dB */
291};
292
293#define MIXART_ANALOG_CAPTURE_LEVEL_MIN 0 /* -96.0 dB + 8.0 dB = -88.0 dB */
294#define MIXART_ANALOG_CAPTURE_LEVEL_MAX 255 /* 31.5 dB + 8.0 dB = 39.5 dB */
295#define MIXART_ANALOG_CAPTURE_ZERO_LEVEL 176 /* -8.0 dB + 8.0 dB = 0.0 dB */
296
297#define MIXART_ANALOG_PLAYBACK_LEVEL_MIN 0 /* -96.0 dB + 1.5 dB = -94.5 dB (possible is down to (-114.0+1.5)dB) */
298#define MIXART_ANALOG_PLAYBACK_LEVEL_MAX 192 /* 0.0 dB + 1.5 dB = 1.5 dB */
299#define MIXART_ANALOG_PLAYBACK_ZERO_LEVEL 189 /* -1.5 dB + 1.5 dB = 0.0 dB */
300
301static int mixart_update_analog_audio_level(mixart_t* chip, int is_capture)
302{
303 int i, err;
304 mixart_msg_t request;
305 mixart_io_level_t io_level;
306 mixart_return_uid_t resp;
307
308 memset(&io_level, 0, sizeof(io_level));
309 io_level.channel = -1; /* left and right */
310
311 for(i=0; i<2; i++) {
312 if(is_capture) {
313 io_level.level[i].analog_level = mixart_analog_level[chip->analog_capture_volume[i]];
314 } else {
315 if(chip->analog_playback_active[i])
316 io_level.level[i].analog_level = mixart_analog_level[chip->analog_playback_volume[i]];
317 else
318 io_level.level[i].analog_level = mixart_analog_level[MIXART_ANALOG_PLAYBACK_LEVEL_MIN];
319 }
320 }
321
322 if(is_capture) request.uid = chip->uid_in_analog_physio;
323 else request.uid = chip->uid_out_analog_physio;
324 request.message_id = MSG_PHYSICALIO_SET_LEVEL;
325 request.data = &io_level;
326 request.size = sizeof(io_level);
327
328 err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
329 if((err<0) || (resp.error_code)) {
330 snd_printk(KERN_DEBUG "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n", chip->chip_idx, is_capture, resp.error_code);
331 return -EINVAL;
332 }
333 return 0;
334}
335
336/*
337 * analog level control
338 */
339static int mixart_analog_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
340{
341 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
342 uinfo->count = 2;
343 if(kcontrol->private_value == 0) { /* playback */
344 uinfo->value.integer.min = MIXART_ANALOG_PLAYBACK_LEVEL_MIN; /* -96 dB */
345 uinfo->value.integer.max = MIXART_ANALOG_PLAYBACK_LEVEL_MAX; /* 0 dB */
346 } else { /* capture */
347 uinfo->value.integer.min = MIXART_ANALOG_CAPTURE_LEVEL_MIN; /* -96 dB */
348 uinfo->value.integer.max = MIXART_ANALOG_CAPTURE_LEVEL_MAX; /* 31.5 dB */
349 }
350 return 0;
351}
352
353static int mixart_analog_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
354{
355 mixart_t *chip = snd_kcontrol_chip(kcontrol);
356 down(&chip->mgr->mixer_mutex);
357 if(kcontrol->private_value == 0) { /* playback */
358 ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
359 ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
360 } else { /* capture */
361 ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
362 ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
363 }
364 up(&chip->mgr->mixer_mutex);
365 return 0;
366}
367
368static int mixart_analog_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
369{
370 mixart_t *chip = snd_kcontrol_chip(kcontrol);
371 int changed = 0;
372 int is_capture, i;
373
374 down(&chip->mgr->mixer_mutex);
375 is_capture = (kcontrol->private_value != 0);
376 for(i=0; i<2; i++) {
377 int new_volume = ucontrol->value.integer.value[i];
378 int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i];
379 if(*stored_volume != new_volume) {
380 *stored_volume = new_volume;
381 changed = 1;
382 }
383 }
384 if(changed) mixart_update_analog_audio_level(chip, is_capture);
385 up(&chip->mgr->mixer_mutex);
386 return changed;
387}
388
389static snd_kcontrol_new_t mixart_control_analog_level = {
390 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
391 /* name will be filled later */
392 .info = mixart_analog_vol_info,
393 .get = mixart_analog_vol_get,
394 .put = mixart_analog_vol_put,
395};
396
397/* shared */
398static int mixart_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
399{
400 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
401 uinfo->count = 2;
402 uinfo->value.integer.min = 0;
403 uinfo->value.integer.max = 1;
404 return 0;
405}
406
407static int mixart_audio_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
408{
409 mixart_t *chip = snd_kcontrol_chip(kcontrol);
410
411 down(&chip->mgr->mixer_mutex);
412 ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
413 ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
414 up(&chip->mgr->mixer_mutex);
415 return 0;
416}
417
418static int mixart_audio_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
419{
420 mixart_t *chip = snd_kcontrol_chip(kcontrol);
421 int i, changed = 0;
422 down(&chip->mgr->mixer_mutex);
423 for(i=0; i<2; i++) {
424 if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
425 chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
426 changed = 1;
427 }
428 }
429 if(changed) mixart_update_analog_audio_level(chip, 0); /* update playback levels */
430 up(&chip->mgr->mixer_mutex);
431 return changed;
432}
433
434static snd_kcontrol_new_t mixart_control_output_switch = {
435 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
436 .name = "Master Playback Switch",
437 .info = mixart_sw_info, /* shared */
438 .get = mixart_audio_sw_get,
439 .put = mixart_audio_sw_put
440};
441
442static u32 mixart_digital_level[256] = {
443 0x00000000, /* [000] = 0.00e+000 = mute if <= -109.5dB */
444 0x366e1c7a, /* [001] = 3.55e-006 = pow(10.0, 0.05 * -109.0dB) */
445 0x367c3860, /* [002] = 3.76e-006 = pow(10.0, 0.05 * -108.5dB) */
446 0x36859525, /* [003] = 3.98e-006 = pow(10.0, 0.05 * -108.0dB) */
447 0x368d7f74, /* [004] = 4.22e-006 = pow(10.0, 0.05 * -107.5dB) */
448 0x3695e1d4, /* [005] = 4.47e-006 = pow(10.0, 0.05 * -107.0dB) */
449 0x369ec362, /* [006] = 4.73e-006 = pow(10.0, 0.05 * -106.5dB) */
450 0x36a82ba8, /* [007] = 5.01e-006 = pow(10.0, 0.05 * -106.0dB) */
451 0x36b222a0, /* [008] = 5.31e-006 = pow(10.0, 0.05 * -105.5dB) */
452 0x36bcb0c1, /* [009] = 5.62e-006 = pow(10.0, 0.05 * -105.0dB) */
453 0x36c7defd, /* [010] = 5.96e-006 = pow(10.0, 0.05 * -104.5dB) */
454 0x36d3b6d3, /* [011] = 6.31e-006 = pow(10.0, 0.05 * -104.0dB) */
455 0x36e0424e, /* [012] = 6.68e-006 = pow(10.0, 0.05 * -103.5dB) */
456 0x36ed8c14, /* [013] = 7.08e-006 = pow(10.0, 0.05 * -103.0dB) */
457 0x36fb9f6c, /* [014] = 7.50e-006 = pow(10.0, 0.05 * -102.5dB) */
458 0x37054423, /* [015] = 7.94e-006 = pow(10.0, 0.05 * -102.0dB) */
459 0x370d29a5, /* [016] = 8.41e-006 = pow(10.0, 0.05 * -101.5dB) */
460 0x371586f0, /* [017] = 8.91e-006 = pow(10.0, 0.05 * -101.0dB) */
461 0x371e631b, /* [018] = 9.44e-006 = pow(10.0, 0.05 * -100.5dB) */
462 0x3727c5ac, /* [019] = 1.00e-005 = pow(10.0, 0.05 * -100.0dB) */
463 0x3731b69a, /* [020] = 1.06e-005 = pow(10.0, 0.05 * -99.5dB) */
464 0x373c3e53, /* [021] = 1.12e-005 = pow(10.0, 0.05 * -99.0dB) */
465 0x374765c8, /* [022] = 1.19e-005 = pow(10.0, 0.05 * -98.5dB) */
466 0x3753366f, /* [023] = 1.26e-005 = pow(10.0, 0.05 * -98.0dB) */
467 0x375fba4f, /* [024] = 1.33e-005 = pow(10.0, 0.05 * -97.5dB) */
468 0x376cfc07, /* [025] = 1.41e-005 = pow(10.0, 0.05 * -97.0dB) */
469 0x377b06d5, /* [026] = 1.50e-005 = pow(10.0, 0.05 * -96.5dB) */
470 0x3784f352, /* [027] = 1.58e-005 = pow(10.0, 0.05 * -96.0dB) */
471 0x378cd40b, /* [028] = 1.68e-005 = pow(10.0, 0.05 * -95.5dB) */
472 0x37952c42, /* [029] = 1.78e-005 = pow(10.0, 0.05 * -95.0dB) */
473 0x379e030e, /* [030] = 1.88e-005 = pow(10.0, 0.05 * -94.5dB) */
474 0x37a75fef, /* [031] = 2.00e-005 = pow(10.0, 0.05 * -94.0dB) */
475 0x37b14ad5, /* [032] = 2.11e-005 = pow(10.0, 0.05 * -93.5dB) */
476 0x37bbcc2c, /* [033] = 2.24e-005 = pow(10.0, 0.05 * -93.0dB) */
477 0x37c6ecdd, /* [034] = 2.37e-005 = pow(10.0, 0.05 * -92.5dB) */
478 0x37d2b65a, /* [035] = 2.51e-005 = pow(10.0, 0.05 * -92.0dB) */
479 0x37df32a3, /* [036] = 2.66e-005 = pow(10.0, 0.05 * -91.5dB) */
480 0x37ec6c50, /* [037] = 2.82e-005 = pow(10.0, 0.05 * -91.0dB) */
481 0x37fa6e9b, /* [038] = 2.99e-005 = pow(10.0, 0.05 * -90.5dB) */
482 0x3804a2b3, /* [039] = 3.16e-005 = pow(10.0, 0.05 * -90.0dB) */
483 0x380c7ea4, /* [040] = 3.35e-005 = pow(10.0, 0.05 * -89.5dB) */
484 0x3814d1cc, /* [041] = 3.55e-005 = pow(10.0, 0.05 * -89.0dB) */
485 0x381da33c, /* [042] = 3.76e-005 = pow(10.0, 0.05 * -88.5dB) */
486 0x3826fa6f, /* [043] = 3.98e-005 = pow(10.0, 0.05 * -88.0dB) */
487 0x3830df51, /* [044] = 4.22e-005 = pow(10.0, 0.05 * -87.5dB) */
488 0x383b5a49, /* [045] = 4.47e-005 = pow(10.0, 0.05 * -87.0dB) */
489 0x3846743b, /* [046] = 4.73e-005 = pow(10.0, 0.05 * -86.5dB) */
490 0x38523692, /* [047] = 5.01e-005 = pow(10.0, 0.05 * -86.0dB) */
491 0x385eab48, /* [048] = 5.31e-005 = pow(10.0, 0.05 * -85.5dB) */
492 0x386bdcf1, /* [049] = 5.62e-005 = pow(10.0, 0.05 * -85.0dB) */
493 0x3879d6bc, /* [050] = 5.96e-005 = pow(10.0, 0.05 * -84.5dB) */
494 0x38845244, /* [051] = 6.31e-005 = pow(10.0, 0.05 * -84.0dB) */
495 0x388c2971, /* [052] = 6.68e-005 = pow(10.0, 0.05 * -83.5dB) */
496 0x3894778d, /* [053] = 7.08e-005 = pow(10.0, 0.05 * -83.0dB) */
497 0x389d43a4, /* [054] = 7.50e-005 = pow(10.0, 0.05 * -82.5dB) */
498 0x38a6952c, /* [055] = 7.94e-005 = pow(10.0, 0.05 * -82.0dB) */
499 0x38b0740f, /* [056] = 8.41e-005 = pow(10.0, 0.05 * -81.5dB) */
500 0x38bae8ac, /* [057] = 8.91e-005 = pow(10.0, 0.05 * -81.0dB) */
501 0x38c5fbe2, /* [058] = 9.44e-005 = pow(10.0, 0.05 * -80.5dB) */
502 0x38d1b717, /* [059] = 1.00e-004 = pow(10.0, 0.05 * -80.0dB) */
503 0x38de2440, /* [060] = 1.06e-004 = pow(10.0, 0.05 * -79.5dB) */
504 0x38eb4de8, /* [061] = 1.12e-004 = pow(10.0, 0.05 * -79.0dB) */
505 0x38f93f3a, /* [062] = 1.19e-004 = pow(10.0, 0.05 * -78.5dB) */
506 0x39040206, /* [063] = 1.26e-004 = pow(10.0, 0.05 * -78.0dB) */
507 0x390bd472, /* [064] = 1.33e-004 = pow(10.0, 0.05 * -77.5dB) */
508 0x39141d84, /* [065] = 1.41e-004 = pow(10.0, 0.05 * -77.0dB) */
509 0x391ce445, /* [066] = 1.50e-004 = pow(10.0, 0.05 * -76.5dB) */
510 0x39263027, /* [067] = 1.58e-004 = pow(10.0, 0.05 * -76.0dB) */
511 0x3930090d, /* [068] = 1.68e-004 = pow(10.0, 0.05 * -75.5dB) */
512 0x393a7753, /* [069] = 1.78e-004 = pow(10.0, 0.05 * -75.0dB) */
513 0x394583d2, /* [070] = 1.88e-004 = pow(10.0, 0.05 * -74.5dB) */
514 0x395137ea, /* [071] = 2.00e-004 = pow(10.0, 0.05 * -74.0dB) */
515 0x395d9d8a, /* [072] = 2.11e-004 = pow(10.0, 0.05 * -73.5dB) */
516 0x396abf37, /* [073] = 2.24e-004 = pow(10.0, 0.05 * -73.0dB) */
517 0x3978a814, /* [074] = 2.37e-004 = pow(10.0, 0.05 * -72.5dB) */
518 0x3983b1f8, /* [075] = 2.51e-004 = pow(10.0, 0.05 * -72.0dB) */
519 0x398b7fa6, /* [076] = 2.66e-004 = pow(10.0, 0.05 * -71.5dB) */
520 0x3993c3b2, /* [077] = 2.82e-004 = pow(10.0, 0.05 * -71.0dB) */
521 0x399c8521, /* [078] = 2.99e-004 = pow(10.0, 0.05 * -70.5dB) */
522 0x39a5cb5f, /* [079] = 3.16e-004 = pow(10.0, 0.05 * -70.0dB) */
523 0x39af9e4d, /* [080] = 3.35e-004 = pow(10.0, 0.05 * -69.5dB) */
524 0x39ba063f, /* [081] = 3.55e-004 = pow(10.0, 0.05 * -69.0dB) */
525 0x39c50c0b, /* [082] = 3.76e-004 = pow(10.0, 0.05 * -68.5dB) */
526 0x39d0b90a, /* [083] = 3.98e-004 = pow(10.0, 0.05 * -68.0dB) */
527 0x39dd1726, /* [084] = 4.22e-004 = pow(10.0, 0.05 * -67.5dB) */
528 0x39ea30db, /* [085] = 4.47e-004 = pow(10.0, 0.05 * -67.0dB) */
529 0x39f81149, /* [086] = 4.73e-004 = pow(10.0, 0.05 * -66.5dB) */
530 0x3a03621b, /* [087] = 5.01e-004 = pow(10.0, 0.05 * -66.0dB) */
531 0x3a0b2b0d, /* [088] = 5.31e-004 = pow(10.0, 0.05 * -65.5dB) */
532 0x3a136a16, /* [089] = 5.62e-004 = pow(10.0, 0.05 * -65.0dB) */
533 0x3a1c2636, /* [090] = 5.96e-004 = pow(10.0, 0.05 * -64.5dB) */
534 0x3a2566d5, /* [091] = 6.31e-004 = pow(10.0, 0.05 * -64.0dB) */
535 0x3a2f33cd, /* [092] = 6.68e-004 = pow(10.0, 0.05 * -63.5dB) */
536 0x3a399570, /* [093] = 7.08e-004 = pow(10.0, 0.05 * -63.0dB) */
537 0x3a44948c, /* [094] = 7.50e-004 = pow(10.0, 0.05 * -62.5dB) */
538 0x3a503a77, /* [095] = 7.94e-004 = pow(10.0, 0.05 * -62.0dB) */
539 0x3a5c9112, /* [096] = 8.41e-004 = pow(10.0, 0.05 * -61.5dB) */
540 0x3a69a2d7, /* [097] = 8.91e-004 = pow(10.0, 0.05 * -61.0dB) */
541 0x3a777ada, /* [098] = 9.44e-004 = pow(10.0, 0.05 * -60.5dB) */
542 0x3a83126f, /* [099] = 1.00e-003 = pow(10.0, 0.05 * -60.0dB) */
543 0x3a8ad6a8, /* [100] = 1.06e-003 = pow(10.0, 0.05 * -59.5dB) */
544 0x3a9310b1, /* [101] = 1.12e-003 = pow(10.0, 0.05 * -59.0dB) */
545 0x3a9bc784, /* [102] = 1.19e-003 = pow(10.0, 0.05 * -58.5dB) */
546 0x3aa50287, /* [103] = 1.26e-003 = pow(10.0, 0.05 * -58.0dB) */
547 0x3aaec98e, /* [104] = 1.33e-003 = pow(10.0, 0.05 * -57.5dB) */
548 0x3ab924e5, /* [105] = 1.41e-003 = pow(10.0, 0.05 * -57.0dB) */
549 0x3ac41d56, /* [106] = 1.50e-003 = pow(10.0, 0.05 * -56.5dB) */
550 0x3acfbc31, /* [107] = 1.58e-003 = pow(10.0, 0.05 * -56.0dB) */
551 0x3adc0b51, /* [108] = 1.68e-003 = pow(10.0, 0.05 * -55.5dB) */
552 0x3ae91528, /* [109] = 1.78e-003 = pow(10.0, 0.05 * -55.0dB) */
553 0x3af6e4c6, /* [110] = 1.88e-003 = pow(10.0, 0.05 * -54.5dB) */
554 0x3b02c2f2, /* [111] = 2.00e-003 = pow(10.0, 0.05 * -54.0dB) */
555 0x3b0a8276, /* [112] = 2.11e-003 = pow(10.0, 0.05 * -53.5dB) */
556 0x3b12b782, /* [113] = 2.24e-003 = pow(10.0, 0.05 * -53.0dB) */
557 0x3b1b690d, /* [114] = 2.37e-003 = pow(10.0, 0.05 * -52.5dB) */
558 0x3b249e76, /* [115] = 2.51e-003 = pow(10.0, 0.05 * -52.0dB) */
559 0x3b2e5f8f, /* [116] = 2.66e-003 = pow(10.0, 0.05 * -51.5dB) */
560 0x3b38b49f, /* [117] = 2.82e-003 = pow(10.0, 0.05 * -51.0dB) */
561 0x3b43a669, /* [118] = 2.99e-003 = pow(10.0, 0.05 * -50.5dB) */
562 0x3b4f3e37, /* [119] = 3.16e-003 = pow(10.0, 0.05 * -50.0dB) */
563 0x3b5b85e0, /* [120] = 3.35e-003 = pow(10.0, 0.05 * -49.5dB) */
564 0x3b6887cf, /* [121] = 3.55e-003 = pow(10.0, 0.05 * -49.0dB) */
565 0x3b764f0e, /* [122] = 3.76e-003 = pow(10.0, 0.05 * -48.5dB) */
566 0x3b8273a6, /* [123] = 3.98e-003 = pow(10.0, 0.05 * -48.0dB) */
567 0x3b8a2e77, /* [124] = 4.22e-003 = pow(10.0, 0.05 * -47.5dB) */
568 0x3b925e89, /* [125] = 4.47e-003 = pow(10.0, 0.05 * -47.0dB) */
569 0x3b9b0ace, /* [126] = 4.73e-003 = pow(10.0, 0.05 * -46.5dB) */
570 0x3ba43aa2, /* [127] = 5.01e-003 = pow(10.0, 0.05 * -46.0dB) */
571 0x3badf5d1, /* [128] = 5.31e-003 = pow(10.0, 0.05 * -45.5dB) */
572 0x3bb8449c, /* [129] = 5.62e-003 = pow(10.0, 0.05 * -45.0dB) */
573 0x3bc32fc3, /* [130] = 5.96e-003 = pow(10.0, 0.05 * -44.5dB) */
574 0x3bcec08a, /* [131] = 6.31e-003 = pow(10.0, 0.05 * -44.0dB) */
575 0x3bdb00c0, /* [132] = 6.68e-003 = pow(10.0, 0.05 * -43.5dB) */
576 0x3be7facc, /* [133] = 7.08e-003 = pow(10.0, 0.05 * -43.0dB) */
577 0x3bf5b9b0, /* [134] = 7.50e-003 = pow(10.0, 0.05 * -42.5dB) */
578 0x3c02248a, /* [135] = 7.94e-003 = pow(10.0, 0.05 * -42.0dB) */
579 0x3c09daac, /* [136] = 8.41e-003 = pow(10.0, 0.05 * -41.5dB) */
580 0x3c1205c6, /* [137] = 8.91e-003 = pow(10.0, 0.05 * -41.0dB) */
581 0x3c1aacc8, /* [138] = 9.44e-003 = pow(10.0, 0.05 * -40.5dB) */
582 0x3c23d70a, /* [139] = 1.00e-002 = pow(10.0, 0.05 * -40.0dB) */
583 0x3c2d8c52, /* [140] = 1.06e-002 = pow(10.0, 0.05 * -39.5dB) */
584 0x3c37d4dd, /* [141] = 1.12e-002 = pow(10.0, 0.05 * -39.0dB) */
585 0x3c42b965, /* [142] = 1.19e-002 = pow(10.0, 0.05 * -38.5dB) */
586 0x3c4e4329, /* [143] = 1.26e-002 = pow(10.0, 0.05 * -38.0dB) */
587 0x3c5a7bf1, /* [144] = 1.33e-002 = pow(10.0, 0.05 * -37.5dB) */
588 0x3c676e1e, /* [145] = 1.41e-002 = pow(10.0, 0.05 * -37.0dB) */
589 0x3c7524ac, /* [146] = 1.50e-002 = pow(10.0, 0.05 * -36.5dB) */
590 0x3c81d59f, /* [147] = 1.58e-002 = pow(10.0, 0.05 * -36.0dB) */
591 0x3c898712, /* [148] = 1.68e-002 = pow(10.0, 0.05 * -35.5dB) */
592 0x3c91ad39, /* [149] = 1.78e-002 = pow(10.0, 0.05 * -35.0dB) */
593 0x3c9a4efc, /* [150] = 1.88e-002 = pow(10.0, 0.05 * -34.5dB) */
594 0x3ca373af, /* [151] = 2.00e-002 = pow(10.0, 0.05 * -34.0dB) */
595 0x3cad2314, /* [152] = 2.11e-002 = pow(10.0, 0.05 * -33.5dB) */
596 0x3cb76563, /* [153] = 2.24e-002 = pow(10.0, 0.05 * -33.0dB) */
597 0x3cc24350, /* [154] = 2.37e-002 = pow(10.0, 0.05 * -32.5dB) */
598 0x3ccdc614, /* [155] = 2.51e-002 = pow(10.0, 0.05 * -32.0dB) */
599 0x3cd9f773, /* [156] = 2.66e-002 = pow(10.0, 0.05 * -31.5dB) */
600 0x3ce6e1c6, /* [157] = 2.82e-002 = pow(10.0, 0.05 * -31.0dB) */
601 0x3cf49003, /* [158] = 2.99e-002 = pow(10.0, 0.05 * -30.5dB) */
602 0x3d0186e2, /* [159] = 3.16e-002 = pow(10.0, 0.05 * -30.0dB) */
603 0x3d0933ac, /* [160] = 3.35e-002 = pow(10.0, 0.05 * -29.5dB) */
604 0x3d1154e1, /* [161] = 3.55e-002 = pow(10.0, 0.05 * -29.0dB) */
605 0x3d19f169, /* [162] = 3.76e-002 = pow(10.0, 0.05 * -28.5dB) */
606 0x3d231090, /* [163] = 3.98e-002 = pow(10.0, 0.05 * -28.0dB) */
607 0x3d2cba15, /* [164] = 4.22e-002 = pow(10.0, 0.05 * -27.5dB) */
608 0x3d36f62b, /* [165] = 4.47e-002 = pow(10.0, 0.05 * -27.0dB) */
609 0x3d41cd81, /* [166] = 4.73e-002 = pow(10.0, 0.05 * -26.5dB) */
610 0x3d4d494a, /* [167] = 5.01e-002 = pow(10.0, 0.05 * -26.0dB) */
611 0x3d597345, /* [168] = 5.31e-002 = pow(10.0, 0.05 * -25.5dB) */
612 0x3d6655c3, /* [169] = 5.62e-002 = pow(10.0, 0.05 * -25.0dB) */
613 0x3d73fbb4, /* [170] = 5.96e-002 = pow(10.0, 0.05 * -24.5dB) */
614 0x3d813856, /* [171] = 6.31e-002 = pow(10.0, 0.05 * -24.0dB) */
615 0x3d88e078, /* [172] = 6.68e-002 = pow(10.0, 0.05 * -23.5dB) */
616 0x3d90fcbf, /* [173] = 7.08e-002 = pow(10.0, 0.05 * -23.0dB) */
617 0x3d99940e, /* [174] = 7.50e-002 = pow(10.0, 0.05 * -22.5dB) */
618 0x3da2adad, /* [175] = 7.94e-002 = pow(10.0, 0.05 * -22.0dB) */
619 0x3dac5156, /* [176] = 8.41e-002 = pow(10.0, 0.05 * -21.5dB) */
620 0x3db68738, /* [177] = 8.91e-002 = pow(10.0, 0.05 * -21.0dB) */
621 0x3dc157fb, /* [178] = 9.44e-002 = pow(10.0, 0.05 * -20.5dB) */
622 0x3dcccccd, /* [179] = 1.00e-001 = pow(10.0, 0.05 * -20.0dB) */
623 0x3dd8ef67, /* [180] = 1.06e-001 = pow(10.0, 0.05 * -19.5dB) */
624 0x3de5ca15, /* [181] = 1.12e-001 = pow(10.0, 0.05 * -19.0dB) */
625 0x3df367bf, /* [182] = 1.19e-001 = pow(10.0, 0.05 * -18.5dB) */
626 0x3e00e9f9, /* [183] = 1.26e-001 = pow(10.0, 0.05 * -18.0dB) */
627 0x3e088d77, /* [184] = 1.33e-001 = pow(10.0, 0.05 * -17.5dB) */
628 0x3e10a4d3, /* [185] = 1.41e-001 = pow(10.0, 0.05 * -17.0dB) */
629 0x3e1936ec, /* [186] = 1.50e-001 = pow(10.0, 0.05 * -16.5dB) */
630 0x3e224b06, /* [187] = 1.58e-001 = pow(10.0, 0.05 * -16.0dB) */
631 0x3e2be8d7, /* [188] = 1.68e-001 = pow(10.0, 0.05 * -15.5dB) */
632 0x3e361887, /* [189] = 1.78e-001 = pow(10.0, 0.05 * -15.0dB) */
633 0x3e40e2bb, /* [190] = 1.88e-001 = pow(10.0, 0.05 * -14.5dB) */
634 0x3e4c509b, /* [191] = 2.00e-001 = pow(10.0, 0.05 * -14.0dB) */
635 0x3e586bd9, /* [192] = 2.11e-001 = pow(10.0, 0.05 * -13.5dB) */
636 0x3e653ebb, /* [193] = 2.24e-001 = pow(10.0, 0.05 * -13.0dB) */
637 0x3e72d424, /* [194] = 2.37e-001 = pow(10.0, 0.05 * -12.5dB) */
638 0x3e809bcc, /* [195] = 2.51e-001 = pow(10.0, 0.05 * -12.0dB) */
639 0x3e883aa8, /* [196] = 2.66e-001 = pow(10.0, 0.05 * -11.5dB) */
640 0x3e904d1c, /* [197] = 2.82e-001 = pow(10.0, 0.05 * -11.0dB) */
641 0x3e98da02, /* [198] = 2.99e-001 = pow(10.0, 0.05 * -10.5dB) */
642 0x3ea1e89b, /* [199] = 3.16e-001 = pow(10.0, 0.05 * -10.0dB) */
643 0x3eab8097, /* [200] = 3.35e-001 = pow(10.0, 0.05 * -9.5dB) */
644 0x3eb5aa1a, /* [201] = 3.55e-001 = pow(10.0, 0.05 * -9.0dB) */
645 0x3ec06dc3, /* [202] = 3.76e-001 = pow(10.0, 0.05 * -8.5dB) */
646 0x3ecbd4b4, /* [203] = 3.98e-001 = pow(10.0, 0.05 * -8.0dB) */
647 0x3ed7e89b, /* [204] = 4.22e-001 = pow(10.0, 0.05 * -7.5dB) */
648 0x3ee4b3b6, /* [205] = 4.47e-001 = pow(10.0, 0.05 * -7.0dB) */
649 0x3ef240e2, /* [206] = 4.73e-001 = pow(10.0, 0.05 * -6.5dB) */
650 0x3f004dce, /* [207] = 5.01e-001 = pow(10.0, 0.05 * -6.0dB) */
651 0x3f07e80b, /* [208] = 5.31e-001 = pow(10.0, 0.05 * -5.5dB) */
652 0x3f0ff59a, /* [209] = 5.62e-001 = pow(10.0, 0.05 * -5.0dB) */
653 0x3f187d50, /* [210] = 5.96e-001 = pow(10.0, 0.05 * -4.5dB) */
654 0x3f21866c, /* [211] = 6.31e-001 = pow(10.0, 0.05 * -4.0dB) */
655 0x3f2b1896, /* [212] = 6.68e-001 = pow(10.0, 0.05 * -3.5dB) */
656 0x3f353bef, /* [213] = 7.08e-001 = pow(10.0, 0.05 * -3.0dB) */
657 0x3f3ff911, /* [214] = 7.50e-001 = pow(10.0, 0.05 * -2.5dB) */
658 0x3f4b5918, /* [215] = 7.94e-001 = pow(10.0, 0.05 * -2.0dB) */
659 0x3f5765ac, /* [216] = 8.41e-001 = pow(10.0, 0.05 * -1.5dB) */
660 0x3f642905, /* [217] = 8.91e-001 = pow(10.0, 0.05 * -1.0dB) */
661 0x3f71adf9, /* [218] = 9.44e-001 = pow(10.0, 0.05 * -0.5dB) */
662 0x3f800000, /* [219] = 1.00e+000 = pow(10.0, 0.05 * 0.0dB) */
663 0x3f8795a0, /* [220] = 1.06e+000 = pow(10.0, 0.05 * 0.5dB) */
664 0x3f8f9e4d, /* [221] = 1.12e+000 = pow(10.0, 0.05 * 1.0dB) */
665 0x3f9820d7, /* [222] = 1.19e+000 = pow(10.0, 0.05 * 1.5dB) */
666 0x3fa12478, /* [223] = 1.26e+000 = pow(10.0, 0.05 * 2.0dB) */
667 0x3faab0d5, /* [224] = 1.33e+000 = pow(10.0, 0.05 * 2.5dB) */
668 0x3fb4ce08, /* [225] = 1.41e+000 = pow(10.0, 0.05 * 3.0dB) */
669 0x3fbf84a6, /* [226] = 1.50e+000 = pow(10.0, 0.05 * 3.5dB) */
670 0x3fcaddc8, /* [227] = 1.58e+000 = pow(10.0, 0.05 * 4.0dB) */
671 0x3fd6e30d, /* [228] = 1.68e+000 = pow(10.0, 0.05 * 4.5dB) */
672 0x3fe39ea9, /* [229] = 1.78e+000 = pow(10.0, 0.05 * 5.0dB) */
673 0x3ff11b6a, /* [230] = 1.88e+000 = pow(10.0, 0.05 * 5.5dB) */
674 0x3fff64c1, /* [231] = 2.00e+000 = pow(10.0, 0.05 * 6.0dB) */
675 0x40074368, /* [232] = 2.11e+000 = pow(10.0, 0.05 * 6.5dB) */
676 0x400f4735, /* [233] = 2.24e+000 = pow(10.0, 0.05 * 7.0dB) */
677 0x4017c496, /* [234] = 2.37e+000 = pow(10.0, 0.05 * 7.5dB) */
678 0x4020c2bf, /* [235] = 2.51e+000 = pow(10.0, 0.05 * 8.0dB) */
679 0x402a4952, /* [236] = 2.66e+000 = pow(10.0, 0.05 * 8.5dB) */
680 0x40346063, /* [237] = 2.82e+000 = pow(10.0, 0.05 * 9.0dB) */
681 0x403f1082, /* [238] = 2.99e+000 = pow(10.0, 0.05 * 9.5dB) */
682 0x404a62c2, /* [239] = 3.16e+000 = pow(10.0, 0.05 * 10.0dB) */
683 0x405660bd, /* [240] = 3.35e+000 = pow(10.0, 0.05 * 10.5dB) */
684 0x406314a0, /* [241] = 3.55e+000 = pow(10.0, 0.05 * 11.0dB) */
685 0x40708933, /* [242] = 3.76e+000 = pow(10.0, 0.05 * 11.5dB) */
686 0x407ec9e1, /* [243] = 3.98e+000 = pow(10.0, 0.05 * 12.0dB) */
687 0x4086f161, /* [244] = 4.22e+000 = pow(10.0, 0.05 * 12.5dB) */
688 0x408ef052, /* [245] = 4.47e+000 = pow(10.0, 0.05 * 13.0dB) */
689 0x4097688d, /* [246] = 4.73e+000 = pow(10.0, 0.05 * 13.5dB) */
690 0x40a06142, /* [247] = 5.01e+000 = pow(10.0, 0.05 * 14.0dB) */
691 0x40a9e20e, /* [248] = 5.31e+000 = pow(10.0, 0.05 * 14.5dB) */
692 0x40b3f300, /* [249] = 5.62e+000 = pow(10.0, 0.05 * 15.0dB) */
693 0x40be9ca5, /* [250] = 5.96e+000 = pow(10.0, 0.05 * 15.5dB) */
694 0x40c9e807, /* [251] = 6.31e+000 = pow(10.0, 0.05 * 16.0dB) */
695 0x40d5debc, /* [252] = 6.68e+000 = pow(10.0, 0.05 * 16.5dB) */
696 0x40e28aeb, /* [253] = 7.08e+000 = pow(10.0, 0.05 * 17.0dB) */
697 0x40eff755, /* [254] = 7.50e+000 = pow(10.0, 0.05 * 17.5dB) */
698 0x40fe2f5e, /* [255] = 7.94e+000 = pow(10.0, 0.05 * 18.0dB) */
699};
700
701#define MIXART_DIGITAL_LEVEL_MIN 0 /* -109.5 dB */
702#define MIXART_DIGITAL_LEVEL_MAX 255 /* 18.0 dB */
703#define MIXART_DIGITAL_ZERO_LEVEL 219 /* 0.0 dB */
704
705
706int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx)
707{
708 int err, i;
709 int volume[2];
710 mixart_msg_t request;
711 mixart_set_out_stream_level_req_t set_level;
712 u32 status;
713 mixart_pipe_t *pipe;
714
715 memset(&set_level, 0, sizeof(set_level));
716 set_level.nb_of_stream = 1;
717 set_level.stream_level.desc.stream_idx = idx;
718
719 if(is_aes) {
720 pipe = &chip->pipe_out_dig; /* AES playback */
721 idx += MIXART_PLAYBACK_STREAMS;
722 } else {
723 pipe = &chip->pipe_out_ana; /* analog playback */
724 }
725
726 /* only when pipe exists ! */
727 if(pipe->status == PIPE_UNDEFINED)
728 return 0;
729
730 set_level.stream_level.desc.uid_pipe = pipe->group_uid;
731
732 for(i=0; i<2; i++) {
733 if(chip->digital_playback_active[idx][i])
734 volume[i] = chip->digital_playback_volume[idx][i];
735 else
736 volume[i] = MIXART_DIGITAL_LEVEL_MIN;
737 }
738
739 set_level.stream_level.out_level.valid_mask1 = MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1 | MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2;
740 set_level.stream_level.out_level.left_to_out1_level = mixart_digital_level[volume[0]];
741 set_level.stream_level.out_level.right_to_out2_level = mixart_digital_level[volume[1]];
742
743 request.message_id = MSG_STREAM_SET_OUT_STREAM_LEVEL;
744 request.uid = (mixart_uid_t){0,0};
745 request.data = &set_level;
746 request.size = sizeof(set_level);
747
748 err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
749 if((err<0) || status) {
750 snd_printk(KERN_DEBUG "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
751 return -EINVAL;
752 }
753 return 0;
754}
755
756int mixart_update_capture_stream_level(mixart_t* chip, int is_aes)
757{
758 int err, i, idx;
759 mixart_pipe_t* pipe;
760 mixart_msg_t request;
761 mixart_set_in_audio_level_req_t set_level;
762 u32 status;
763
764 if(is_aes) {
765 idx = 1;
766 pipe = &chip->pipe_in_dig;
767 } else {
768 idx = 0;
769 pipe = &chip->pipe_in_ana;
770 }
771
772 /* only when pipe exists ! */
773 if(pipe->status == PIPE_UNDEFINED)
774 return 0;
775
776 memset(&set_level, 0, sizeof(set_level));
777 set_level.audio_count = 2;
778 set_level.level[0].connector = pipe->uid_left_connector;
779 set_level.level[1].connector = pipe->uid_right_connector;
780
781 for(i=0; i<2; i++) {
782 set_level.level[i].valid_mask1 = MIXART_AUDIO_LEVEL_DIGITAL_MASK;
783 set_level.level[i].digital_level = mixart_digital_level[chip->digital_capture_volume[idx][i]];
784 }
785
786 request.message_id = MSG_STREAM_SET_IN_AUDIO_LEVEL;
787 request.uid = (mixart_uid_t){0,0};
788 request.data = &set_level;
789 request.size = sizeof(set_level);
790
791 err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
792 if((err<0) || status) {
793 snd_printk(KERN_DEBUG "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
794 return -EINVAL;
795 }
796 return 0;
797}
798
799
800/* shared */
801static int mixart_digital_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
802{
803 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
804 uinfo->count = 2;
805 uinfo->value.integer.min = MIXART_DIGITAL_LEVEL_MIN; /* -109.5 dB */
806 uinfo->value.integer.max = MIXART_DIGITAL_LEVEL_MAX; /* 18.0 dB */
807 return 0;
808}
809
810#define MIXART_VOL_REC_MASK 1
811#define MIXART_VOL_AES_MASK 2
812
813static int mixart_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
814{
815 mixart_t *chip = snd_kcontrol_chip(kcontrol);
816 int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
817 int *stored_volume;
818 int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
819 int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
820 down(&chip->mgr->mixer_mutex);
821 if(is_capture) {
822 if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */
823 else stored_volume = chip->digital_capture_volume[0]; /* analog capture */
824 } else {
825 snd_assert ( idx < MIXART_PLAYBACK_STREAMS );
826 if(is_aes) stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
827 else stored_volume = chip->digital_playback_volume[idx]; /* analog playback */
828 }
829 ucontrol->value.integer.value[0] = stored_volume[0];
830 ucontrol->value.integer.value[1] = stored_volume[1];
831 up(&chip->mgr->mixer_mutex);
832 return 0;
833}
834
835static int mixart_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
836{
837 mixart_t *chip = snd_kcontrol_chip(kcontrol);
838 int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
839 int changed = 0;
840 int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
841 int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
842 int* stored_volume;
843 int i;
844 down(&chip->mgr->mixer_mutex);
845 if(is_capture) {
846 if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */
847 else stored_volume = chip->digital_capture_volume[0]; /* analog capture */
848 } else {
849 snd_assert ( idx < MIXART_PLAYBACK_STREAMS );
850 if(is_aes) stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
851 else stored_volume = chip->digital_playback_volume[idx]; /* analog playback */
852 }
853 for(i=0; i<2; i++) {
854 if(stored_volume[i] != ucontrol->value.integer.value[i]) {
855 stored_volume[i] = ucontrol->value.integer.value[i];
856 changed = 1;
857 }
858 }
859 if(changed) {
860 if(is_capture) mixart_update_capture_stream_level(chip, is_aes);
861 else mixart_update_playback_stream_level(chip, is_aes, idx);
862 }
863 up(&chip->mgr->mixer_mutex);
864 return changed;
865}
866
867static snd_kcontrol_new_t snd_mixart_pcm_vol =
868{
869 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
870 /* name will be filled later */
871 /* count will be filled later */
872 .info = mixart_digital_vol_info, /* shared */
873 .get = mixart_pcm_vol_get,
874 .put = mixart_pcm_vol_put,
875};
876
877
878static int mixart_pcm_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
879{
880 mixart_t *chip = snd_kcontrol_chip(kcontrol);
881 int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
882 snd_assert ( idx < MIXART_PLAYBACK_STREAMS );
883 down(&chip->mgr->mixer_mutex);
884 if(kcontrol->private_value & MIXART_VOL_AES_MASK) /* AES playback */
885 idx += MIXART_PLAYBACK_STREAMS;
886 ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
887 ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
888 up(&chip->mgr->mixer_mutex);
889 return 0;
890}
891
892static int mixart_pcm_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
893{
894 mixart_t *chip = snd_kcontrol_chip(kcontrol);
895 int changed = 0;
896 int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
897 int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
898 int i, j;
899 snd_assert ( idx < MIXART_PLAYBACK_STREAMS );
900 down(&chip->mgr->mixer_mutex);
901 j = idx;
902 if(is_aes) j += MIXART_PLAYBACK_STREAMS;
903 for(i=0; i<2; i++) {
904 if(chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) {
905 chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i];
906 changed = 1;
907 }
908 }
909 if(changed) mixart_update_playback_stream_level(chip, is_aes, idx);
910 up(&chip->mgr->mixer_mutex);
911 return changed;
912}
913
914static snd_kcontrol_new_t mixart_control_pcm_switch = {
915 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
916 /* name will be filled later */
917 .count = MIXART_PLAYBACK_STREAMS,
918 .info = mixart_sw_info, /* shared */
919 .get = mixart_pcm_sw_get,
920 .put = mixart_pcm_sw_put
921};
922
923static int mixart_update_monitoring(mixart_t* chip, int channel)
924{
925 int err;
926 mixart_msg_t request;
927 mixart_set_out_audio_level_t audio_level;
928 u32 resp;
929
930 if(chip->pipe_out_ana.status == PIPE_UNDEFINED)
931 return -EINVAL; /* no pipe defined */
932
933 if(!channel) request.uid = chip->pipe_out_ana.uid_left_connector;
934 else request.uid = chip->pipe_out_ana.uid_right_connector;
935 request.message_id = MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL;
936 request.data = &audio_level;
937 request.size = sizeof(audio_level);
938
939 memset(&audio_level, 0, sizeof(audio_level));
940 audio_level.valid_mask1 = MIXART_AUDIO_LEVEL_MONITOR_MASK | MIXART_AUDIO_LEVEL_MUTE_M1_MASK;
941 audio_level.monitor_level = mixart_digital_level[chip->monitoring_volume[channel!=0]];
942 audio_level.monitor_mute1 = !chip->monitoring_active[channel!=0];
943
944 err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
945 if((err<0) || resp) {
946 snd_printk(KERN_DEBUG "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n", chip->chip_idx, resp);
947 return -EINVAL;
948 }
949 return 0;
950}
951
952/*
953 * monitoring level control
954 */
955
956static int mixart_monitor_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
957{
958 mixart_t *chip = snd_kcontrol_chip(kcontrol);
959 down(&chip->mgr->mixer_mutex);
960 ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
961 ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
962 up(&chip->mgr->mixer_mutex);
963 return 0;
964}
965
966static int mixart_monitor_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
967{
968 mixart_t *chip = snd_kcontrol_chip(kcontrol);
969 int changed = 0;
970 int i;
971 down(&chip->mgr->mixer_mutex);
972 for(i=0; i<2; i++) {
973 if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
974 chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
975 mixart_update_monitoring(chip, i);
976 changed = 1;
977 }
978 }
979 up(&chip->mgr->mixer_mutex);
980 return changed;
981}
982
983static snd_kcontrol_new_t mixart_control_monitor_vol = {
984 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
985 .name = "Monitoring Volume",
986 .info = mixart_digital_vol_info, /* shared */
987 .get = mixart_monitor_vol_get,
988 .put = mixart_monitor_vol_put,
989};
990
991/*
992 * monitoring switch control
993 */
994
995static int mixart_monitor_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
996{
997 mixart_t *chip = snd_kcontrol_chip(kcontrol);
998 down(&chip->mgr->mixer_mutex);
999 ucontrol->value.integer.value[0] = chip->monitoring_active[0];
1000 ucontrol->value.integer.value[1] = chip->monitoring_active[1];
1001 up(&chip->mgr->mixer_mutex);
1002 return 0;
1003}
1004
1005static int mixart_monitor_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1006{
1007 mixart_t *chip = snd_kcontrol_chip(kcontrol);
1008 int changed = 0;
1009 int i;
1010 down(&chip->mgr->mixer_mutex);
1011 for(i=0; i<2; i++) {
1012 if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
1013 chip->monitoring_active[i] = ucontrol->value.integer.value[i];
1014 changed |= (1<<i); /* mask 0x01 ans 0x02 */
1015 }
1016 }
1017 if(changed) {
1018 /* allocate or release resources for monitoring */
1019 int allocate = chip->monitoring_active[0] || chip->monitoring_active[1];
1020 if(allocate) {
1021 snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 0, 1); /* allocate the playback pipe for monitoring */
1022 snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 1, 1); /* allocate the capture pipe for monitoring */
1023 }
1024 if(changed & 0x01) mixart_update_monitoring(chip, 0);
1025 if(changed & 0x02) mixart_update_monitoring(chip, 1);
1026 if(!allocate) {
1027 snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_in_ana, 1); /* release the capture pipe for monitoring */
1028 snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_out_ana, 1); /* release the playback pipe for monitoring */
1029 }
1030 }
1031
1032 up(&chip->mgr->mixer_mutex);
1033 return (changed != 0);
1034}
1035
1036static snd_kcontrol_new_t mixart_control_monitor_sw = {
1037 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1038 .name = "Monitoring Switch",
1039 .info = mixart_sw_info, /* shared */
1040 .get = mixart_monitor_sw_get,
1041 .put = mixart_monitor_sw_put
1042};
1043
1044
1045static void mixart_reset_audio_levels(mixart_t *chip)
1046{
1047 /* analog volumes can be set even if there is no pipe */
1048 mixart_update_analog_audio_level(chip, 0);
1049 /* analog levels for capture only on the first two chips */
1050 if(chip->chip_idx < 2) {
1051 mixart_update_analog_audio_level(chip, 1);
1052 }
1053 return;
1054}
1055
1056
1057int snd_mixart_create_mixer(mixart_mgr_t *mgr)
1058{
1059 mixart_t *chip;
1060 int err, i;
1061
1062 init_MUTEX(&mgr->mixer_mutex); /* can be in another place */
1063
1064 for(i=0; i<mgr->num_cards; i++) {
1065 snd_kcontrol_new_t temp;
1066 chip = mgr->chip[i];
1067
1068 /* analog output level control */
1069 temp = mixart_control_analog_level;
1070 temp.name = "Master Playback Volume";
1071 temp.private_value = 0; /* playback */
1072 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
1073 return err;
1074 /* output mute controls */
1075 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_output_switch, chip))) < 0)
1076 return err;
1077
1078 /* analog input level control only on first two chips !*/
1079 if(i<2) {
1080 temp = mixart_control_analog_level;
1081 temp.name = "Master Capture Volume";
1082 temp.private_value = 1; /* capture */
1083 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
1084 return err;
1085 }
1086
1087 temp = snd_mixart_pcm_vol;
1088 temp.name = "PCM Playback Volume";
1089 temp.count = MIXART_PLAYBACK_STREAMS;
1090 temp.private_value = 0; /* playback analog */
1091 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
1092 return err;
1093
1094 temp.name = "PCM Capture Volume";
1095 temp.count = 1;
1096 temp.private_value = MIXART_VOL_REC_MASK; /* capture analog */
1097 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
1098 return err;
1099
1100 if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
1101 temp.name = "AES Playback Volume";
1102 temp.count = MIXART_PLAYBACK_STREAMS;
1103 temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */
1104 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
1105 return err;
1106
1107 temp.name = "AES Capture Volume";
1108 temp.count = 0;
1109 temp.private_value = MIXART_VOL_REC_MASK | MIXART_VOL_AES_MASK; /* capture AES/EBU */
1110 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
1111 return err;
1112 }
1113 temp = mixart_control_pcm_switch;
1114 temp.name = "PCM Playback Switch";
1115 temp.private_value = 0; /* playback analog */
1116 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
1117 return err;
1118
1119 if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
1120 temp.name = "AES Playback Switch";
1121 temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */
1122 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
1123 return err;
1124 }
1125
1126 /* monitoring */
1127 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_vol, chip))) < 0)
1128 return err;
1129 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_sw, chip))) < 0)
1130 return err;
1131
1132 /* init all mixer data and program the master volumes/switches */
1133 mixart_reset_audio_levels(chip);
1134 }
1135 return 0;
1136}
diff --git a/sound/pci/mixart/mixart_mixer.h b/sound/pci/mixart/mixart_mixer.h
new file mode 100644
index 000000000000..b4d9535087c4
--- /dev/null
+++ b/sound/pci/mixart/mixart_mixer.h
@@ -0,0 +1,31 @@
1/*
2 * Driver for Digigram miXart soundcards
3 *
4 * include file for mixer
5 *
6 * Copyright (c) 2003 by Digigram <alsa@digigram.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef __SOUND_MIXART_MIXER_H
24#define __SOUND_MIXART_MIXER_H
25
26/* exported */
27int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx);
28int mixart_update_capture_stream_level(mixart_t* chip, int is_aes);
29int snd_mixart_create_mixer(mixart_mgr_t* mgr);
30
31#endif /* __SOUND_MIXART_MIXER_H */