Pull xpc-disengage into release branch
[linux-2.6] / sound / pci / mixart / mixart.c
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
42 MODULE_AUTHOR("Digigram <alsa@digigram.com>");
43 MODULE_DESCRIPTION("Digigram " CARD_NAME);
44 MODULE_LICENSE("GPL");
45 MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}");
46
47 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;             /* Index 0-MAX */
48 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;              /* ID for this card */
49 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
50
51 module_param_array(index, int, NULL, 0444);
52 MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard.");
53 module_param_array(id, charp, NULL, 0444);
54 MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard.");
55 module_param_array(enable, bool, NULL, 0444);
56 MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
57
58 /*
59  */
60
61 static struct pci_device_id snd_mixart_ids[] = {
62         { 0x1057, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* MC8240 */
63         { 0, }
64 };
65
66 MODULE_DEVICE_TABLE(pci, snd_mixart_ids);
67
68
69 static 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
159 static 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  */
211 mixart_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
318 int 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
366 static 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
402 static 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
446 static int mixart_sync_nonblock_events(mixart_mgr_t *mgr)
447 {
448         unsigned long timeout = jiffies + HZ;
449         while (atomic_read(&mgr->msg_processed) > 0) {
450                 if (time_after(jiffies, 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  */
463 static 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
489 static 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  */
572 static 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
632 static 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  */
645 static 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
666 static 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
688 static 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
763 static 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
842 static 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
872 static 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
882 static 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
893 static 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
904 static 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  */
925 static 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  */
956 static 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
984 static int snd_mixart_chip_free(mixart_t *chip)
985 {
986         kfree(chip);
987         return 0;
988 }
989
990 static 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  */
999 static 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 = kzalloc(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
1027 int 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  */
1048 static 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  */
1096 static 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
1122 static 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  */
1151 static 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  */
1170 static 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
1186 static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = {
1187         .read   = snd_mixart_BA0_read,
1188         .llseek = snd_mixart_BA0_llseek
1189 };
1190
1191 static 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
1197 static 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
1233 static 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  */
1263 static 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 = kzalloc(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
1419 static 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
1425 static struct pci_driver driver = {
1426         .name = "Digigram miXart",
1427         .owner = THIS_MODULE,
1428         .id_table = snd_mixart_ids,
1429         .probe = snd_mixart_probe,
1430         .remove = __devexit_p(snd_mixart_remove),
1431 };
1432
1433 static int __init alsa_card_mixart_init(void)
1434 {
1435         return pci_register_driver(&driver);
1436 }
1437
1438 static void __exit alsa_card_mixart_exit(void)
1439 {
1440         pci_unregister_driver(&driver);
1441 }
1442
1443 module_init(alsa_card_mixart_init)
1444 module_exit(alsa_card_mixart_exit)