Blame view

sound/pci/mixart/mixart_hwdep.c 16.7 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
  /*
   * Driver for Digigram miXart soundcards
   *
   * DSP firmware management
   *
   * Copyright (c) 2003 by Digigram <alsa@digigram.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
  #include <linux/interrupt.h>
  #include <linux/pci.h>
  #include <linux/firmware.h>
44052e0d9   Frank Lichtenheld   mixart: Add missi...
12
  #include <linux/vmalloc.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
da155d5b4   Paul Gortmaker   sound: Add module...
14
  #include <linux/module.h>
6cbbfe1c8   Takashi Iwai   ALSA: Include lin...
15
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
21
22
23
24
25
  #include <sound/core.h>
  #include "mixart.h"
  #include "mixart_mixer.h"
  #include "mixart_core.h"
  #include "mixart_hwdep.h"
  
  
  /**
   * wait for a value on a peudo register, exit with a timeout
   *
3f60c87d1   Takashi Iwai   ALSA: mixart: Fix...
26
27
28
29
30
   * @mgr: pointer to miXart manager structure
   * @offset: unsigned pseudo_register base + offset of value
   * @is_egal: wait for the equal value
   * @value: value
   * @timeout: timeout in centisenconds
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
   */
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
32
33
34
  static int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr,
  					       u32 offset, int is_egal,
  					       u32 value, unsigned long timeout)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  {
  	unsigned long end_time = jiffies + (timeout * HZ / 100);
  	u32 read;
  
  	do {	/* we may take too long time in this loop.
  		 * so give controls back to kernel if needed.
  		 */
  		cond_resched();
  
  		read = readl_be( MIXART_MEM( mgr, offset ));
  		if(is_egal) {
  			if(read == value) return 0;
  		}
  		else { /* wait for different value */
  			if(read != value) return 0;
  		}
  	} while ( time_after_eq(end_time, jiffies) );
  
  	return -EBUSY;
  }
  
  
  /*
    structures needed to upload elf code packets 
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
  struct snd_mixart_elf32_ehdr {
  	u8      e_ident[16];
0e7ca66a9   Takashi Iwai   ALSA: mixart: Pro...
62
63
64
65
66
67
68
69
70
71
72
73
74
  	__be16  e_type;
  	__be16  e_machine;
  	__be32  e_version;
  	__be32  e_entry;
  	__be32  e_phoff;
  	__be32  e_shoff;
  	__be32  e_flags;
  	__be16  e_ehsize;
  	__be16  e_phentsize;
  	__be16  e_phnum;
  	__be16  e_shentsize;
  	__be16  e_shnum;
  	__be16  e_shstrndx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  struct snd_mixart_elf32_phdr {
0e7ca66a9   Takashi Iwai   ALSA: mixart: Pro...
77
78
79
80
81
82
83
84
  	__be32  p_type;
  	__be32  p_offset;
  	__be32  p_vaddr;
  	__be32  p_paddr;
  	__be32  p_filesz;
  	__be32  p_memsz;
  	__be32  p_flags;
  	__be32  p_align;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  };
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
86
  static int mixart_load_elf(struct mixart_mgr *mgr, const struct firmware *dsp )
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
  {
  	char                    elf32_magic_number[4] = {0x7f,'E','L','F'};
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
89
  	struct snd_mixart_elf32_ehdr *elf_header;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  	int                     i;
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
91
  	elf_header = (struct snd_mixart_elf32_ehdr *)dsp->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
  	for( i=0; i<4; i++ )
  		if ( elf32_magic_number[i] != elf_header->e_ident[i] )
  			return -EINVAL;
  
  	if( elf_header->e_phoff != 0 ) {
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
97
  		struct snd_mixart_elf32_phdr     elf_programheader;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  
  		for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {
  			u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));
  
  			memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );
  
  			if(elf_programheader.p_type != 0) {
  				if( elf_programheader.p_filesz != 0 ) {
  					memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
  						     dsp->data + be32_to_cpu( elf_programheader.p_offset ),
  						     be32_to_cpu( elf_programheader.p_filesz ));
  				}
  			}
  		}
  	}
  	return 0;
  }
  
  /*
   * get basic information and init miXart
   */
  
  /* audio IDs for request to the board */
  #define MIXART_FIRST_ANA_AUDIO_ID       0
  #define MIXART_FIRST_DIG_AUDIO_ID       8
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
123
  static int mixart_enum_connectors(struct mixart_mgr *mgr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
  {
  	u32 k;
  	int err;
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
127
128
129
130
  	struct mixart_msg request;
  	struct mixart_enum_connector_resp *connector;
  	struct mixart_audio_info_req  *audio_info_req;
  	struct mixart_audio_info_resp *audio_info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  
  	connector = kmalloc(sizeof(*connector), GFP_KERNEL);
  	audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);
  	audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);
  	if (! connector || ! audio_info_req || ! audio_info) {
  		err = -ENOMEM;
  		goto __error;
  	}
  
  	audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
  	audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
  	audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
  
  	request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
145
  	request.uid = (struct mixart_uid){0,0};  /* board num = 0 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
  	request.data = NULL;
  	request.size = 0;
  
  	err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
  	if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
151
152
153
  		dev_err(&mgr->pci->dev,
  			"error MSG_SYSTEM_ENUM_PLAY_CONNECTOR
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
  		err = -EINVAL;
  		goto __error;
  	}
  
  	for(k=0; k < connector->uid_count; k++) {
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
159
  		struct mixart_pipe *pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
165
166
167
168
169
170
  
  		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
  			pipe = &mgr->chip[k/2]->pipe_out_ana;
  		} else {
  			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
  		}
  		if(k & 1) {
  			pipe->uid_right_connector = connector->uid[k];   /* odd */
  		} else {
  			pipe->uid_left_connector = connector->uid[k];    /* even */
  		}
6414e35de   Takashi Iwai   ALSA: mixart: Use...
171
172
  		/* dev_dbg(&mgr->pci->dev, "playback connector[%d].object_id = %x
  ", k, connector->uid[k].object_id); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
178
179
180
181
  
  		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
  		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
  		request.uid = connector->uid[k];
  		request.data = audio_info_req;
  		request.size = sizeof(*audio_info_req);
  
  		err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
  		if( err < 0 ) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
182
183
184
  			dev_err(&mgr->pci->dev,
  				"error MSG_CONNECTOR_GET_AUDIO_INFO
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
  			goto __error;
  		}
6414e35de   Takashi Iwai   ALSA: mixart: Use...
187
188
  		/*dev_dbg(&mgr->pci->dev, "play  analog_info.analog_level_present = %x
  ", audio_info->info.analog_info.analog_level_present);*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
  	}
  
  	request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
192
  	request.uid = (struct mixart_uid){0,0};  /* board num = 0 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
  	request.data = NULL;
  	request.size = 0;
  
  	err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
  	if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
198
199
200
  		dev_err(&mgr->pci->dev,
  			"error MSG_SYSTEM_ENUM_RECORD_CONNECTOR
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
205
  		err = -EINVAL;
  		goto __error;
  	}
  
  	for(k=0; k < connector->uid_count; k++) {
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
206
  		struct mixart_pipe *pipe;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
213
214
215
216
217
  
  		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
  			pipe = &mgr->chip[k/2]->pipe_in_ana;
  		} else {
  			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
  		}
  		if(k & 1) {
  			pipe->uid_right_connector = connector->uid[k];   /* odd */
  		} else {
  			pipe->uid_left_connector = connector->uid[k];    /* even */
  		}
6414e35de   Takashi Iwai   ALSA: mixart: Use...
218
219
  		/* dev_dbg(&mgr->pci->dev, "capture connector[%d].object_id = %x
  ", k, connector->uid[k].object_id); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
224
225
226
227
228
  
  		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
  		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
  		request.uid = connector->uid[k];
  		request.data = audio_info_req;
  		request.size = sizeof(*audio_info_req);
  
  		err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
  		if( err < 0 ) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
229
230
231
  			dev_err(&mgr->pci->dev,
  				"error MSG_CONNECTOR_GET_AUDIO_INFO
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
  			goto __error;
  		}
6414e35de   Takashi Iwai   ALSA: mixart: Use...
234
235
  		/*dev_dbg(&mgr->pci->dev, "rec  analog_info.analog_level_present = %x
  ", audio_info->info.analog_info.analog_level_present);*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
239
240
241
242
243
244
245
  	}
  	err = 0;
  
   __error:
  	kfree(connector);
  	kfree(audio_info_req);
  	kfree(audio_info);
  
  	return err;
  }
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
246
  static int mixart_enum_physio(struct mixart_mgr *mgr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
  {
  	u32 k;
  	int err;
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
250
251
252
253
  	struct mixart_msg request;
  	struct mixart_uid get_console_mgr;
  	struct mixart_return_uid console_mgr;
  	struct mixart_uid_enumeration phys_io;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
256
257
258
259
260
261
262
263
264
265
266
  
  	/* get the uid for the console manager */
  	get_console_mgr.object_id = 0;
  	get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */
  
  	request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
  	request.uid = get_console_mgr;
  	request.data = &get_console_mgr;
  	request.size = sizeof(get_console_mgr);
  
  	err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
  
  	if( (err < 0) || (console_mgr.error_code != 0) ) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
267
268
269
270
  		dev_dbg(&mgr->pci->dev,
  			"error MSG_CONSOLE_GET_CLOCK_UID : err=%x
  ",
  			console_mgr.error_code);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
  		return -EINVAL;
  	}
  
  	/* used later for clock issues ! */
  	mgr->uid_console_manager = console_mgr.uid;
  
  	request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
278
  	request.uid = (struct mixart_uid){0,0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
  	request.data = &console_mgr.uid;
  	request.size = sizeof(console_mgr.uid);
  
  	err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
  	if( (err < 0) || ( phys_io.error_code != 0 ) ) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
284
285
286
287
  		dev_err(&mgr->pci->dev,
  			"error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)
  ",
  			err, phys_io.error_code);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
  		return -EINVAL;
  	}
da3cec35d   Takashi Iwai   ALSA: Kill snd_as...
290
291
292
  	/* min 2 phys io per card (analog in + analog out) */
  	if (phys_io.nb_uid < MIXART_MAX_CARDS * 2)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
297
298
299
300
  
  	for(k=0; k<mgr->num_cards; k++) {
  		mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
  		mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k]; 
  	}
  
  	return 0;
  }
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
301
  static int mixart_first_init(struct mixart_mgr *mgr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
  {
  	u32 k;
  	int err;
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
305
  	struct mixart_msg request;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
313
  
  	if((err = mixart_enum_connectors(mgr)) < 0) return err;
  
  	if((err = mixart_enum_physio(mgr)) < 0) return err;
  
  	/* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */
  	/* though why not here */
  	request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
314
  	request.uid = (struct mixart_uid){0,0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
318
319
  	request.data = NULL;
  	request.size = 0;
  	/* this command has no data. response is a 32 bit status */
  	err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
  	if( (err < 0) || (k != 0) ) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
320
321
  		dev_err(&mgr->pci->dev, "error MSG_SYSTEM_SEND_SYNCHRO_CMD
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
326
327
328
329
330
  		return err == 0 ? -EINVAL : err;
  	}
  
  	return 0;
  }
  
  
  /* firmware base addresses (when hard coded) */
  #define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS   0x00600000
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
331
  static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmware *dsp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
337
338
339
340
341
342
343
344
  {
  	int           err, card_index;
  	u32           status_xilinx, status_elf, status_daught;
  	u32           val;
  
  	/* read motherboard xilinx status */
  	status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
  	/* read elf status */
  	status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
  	/* read daughterboard xilinx status */
  	status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
  
  	/* motherboard xilinx status 5 will say that the board is performing a reset */
ee419653a   Takashi Iwai   ALSA: Fix missing...
345
  	if (status_xilinx == 5) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
346
347
  		dev_err(&mgr->pci->dev, "miXart is resetting !
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
353
354
  		return -EAGAIN; /* try again later */
  	}
  
  	switch (index)   {
  	case MIXART_MOTHERBOARD_XLX_INDEX:
  
  		/* xilinx already loaded ? */ 
ee419653a   Takashi Iwai   ALSA: Fix missing...
355
  		if (status_xilinx == 4) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
356
357
  			dev_dbg(&mgr->pci->dev, "xilinx is already loaded !
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
  			return 0;
  		}
  		/* the status should be 0 == "idle" */
ee419653a   Takashi Iwai   ALSA: Fix missing...
361
  		if (status_xilinx != 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
362
363
364
  			dev_err(&mgr->pci->dev,
  				"xilinx load error ! status = %d
  ",
ee419653a   Takashi Iwai   ALSA: Fix missing...
365
  				   status_xilinx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
  			return -EIO; /* modprob -r may help ? */
  		}
  
  		/* check xilinx validity */
da3cec35d   Takashi Iwai   ALSA: Kill snd_as...
370
371
372
373
  		if (((u32*)(dsp->data))[0] == 0xffffffff)
  			return -EINVAL;
  		if (dsp->size % 4)
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  
  		/* set xilinx status to copying */
  		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
  
  		/* setup xilinx base address */
  		writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
  		/* setup code size for xilinx file */
  		writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
  
  		/* copy xilinx code */
  		memcpy_toio(  MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS),  dsp->data,  dsp->size);
      
  		/* set xilinx status to copy finished */
  		writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
  
  		/* return, because no further processing needed */
  		return 0;
  
  	case MIXART_MOTHERBOARD_ELF_INDEX:
ee419653a   Takashi Iwai   ALSA: Fix missing...
393
  		if (status_elf == 4) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
394
395
  			dev_dbg(&mgr->pci->dev, "elf file already loaded !
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
  			return 0;
  		}
  
  		/* the status should be 0 == "idle" */
ee419653a   Takashi Iwai   ALSA: Fix missing...
400
  		if (status_elf != 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
401
402
403
  			dev_err(&mgr->pci->dev,
  				"elf load error ! status = %d
  ",
ee419653a   Takashi Iwai   ALSA: Fix missing...
404
  				   status_elf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
408
409
410
  			return -EIO; /* modprob -r may help ? */
  		}
  
  		/* wait for xilinx status == 4 */
  		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
  		if (err < 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
411
  			dev_err(&mgr->pci->dev, "xilinx was not loaded or "
ee419653a   Takashi Iwai   ALSA: Fix missing...
412
413
  				   "could not be started
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  			return err;
  		}
  
  		/* init some data on the card */
  		writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */
  		writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) );         /* reset pointer to flow table on miXart */
  
  		/* set elf status to copying */
  		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
  
  		/* process the copying of the elf packets */
  		err = mixart_load_elf( mgr, dsp );
  		if (err < 0) return err;
  
  		/* set elf status to copy finished */
  		writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
  
  		/* wait for elf status == 4 */
  		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
  		if (err < 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
434
435
  			dev_err(&mgr->pci->dev, "elf could not be started
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
439
440
441
442
443
444
445
446
447
  			return err;
  		}
  
  		/* miXart waits at this point on the pointer to the flow table */
  		writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */
  
  		return 0;  /* return, another xilinx file has to be loaded before */
  
  	case MIXART_AESEBUBOARD_XLX_INDEX:
  	default:
  
  		/* elf and xilinx should be loaded */
ee419653a   Takashi Iwai   ALSA: Fix missing...
448
  		if (status_elf != 4 || status_xilinx != 4) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
449
  			dev_err(&mgr->pci->dev, "xilinx or elf not "
ee419653a   Takashi Iwai   ALSA: Fix missing...
450
451
  			       "successfully loaded
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
456
457
  			return -EIO; /* modprob -r may help ? */
  		}
  
  		/* wait for daughter detection != 0 */
  		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
  		if (err < 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
458
459
  			dev_err(&mgr->pci->dev, "error starting elf file
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  			return err;
  		}
  
  		/* the board type can now be retrieved */
  		mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
  
  		if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
  			break;  /* no daughter board; the file does not have to be loaded, continue after the switch */
  
  		/* only if aesebu daughter board presence (elf code must run)  */ 
  		if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
  			return -EINVAL;
  
  		/* daughter should be idle */
ee419653a   Takashi Iwai   ALSA: Fix missing...
474
  		if (status_daught != 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
475
476
477
  			dev_err(&mgr->pci->dev,
  				"daughter load error ! status = %d
  ",
ee419653a   Takashi Iwai   ALSA: Fix missing...
478
  			       status_daught);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
  			return -EIO; /* modprob -r may help ? */
  		}
   
  		/* check daughterboard xilinx validity */
da3cec35d   Takashi Iwai   ALSA: Kill snd_as...
483
484
485
486
  		if (((u32*)(dsp->data))[0] == 0xffffffff)
  			return -EINVAL;
  		if (dsp->size % 4)
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
491
492
493
494
495
496
  
  		/* inform mixart about the size of the file */
  		writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
  
  		/* set daughterboard status to 1 */
  		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
  
  		/* wait for status == 2 */
  		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
  		if (err < 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
497
498
  			dev_err(&mgr->pci->dev, "daughter board load error
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
502
503
  			return err;
  		}
  
  		/* get the address where to write the file */
  		val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
da3cec35d   Takashi Iwai   ALSA: Kill snd_as...
504
505
  		if (!val)
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  
  		/* copy daughterboard xilinx code */
  		memcpy_toio(  MIXART_MEM( mgr, val),  dsp->data,  dsp->size);
  
  		/* set daughterboard status to 4 */
  		writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
  
  		/* continue with init */
  		break;
  	} /* end of switch file index*/
  
          /* wait for daughter status == 3 */
          err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
          if (err < 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
520
  		dev_err(&mgr->pci->dev,
ee419653a   Takashi Iwai   ALSA: Fix missing...
521
522
  			   "daughter board could not be initialised
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
527
528
529
530
531
  		return err;
  	}
  
  	/* init mailbox (communication with embedded) */
  	snd_mixart_init_mailbox(mgr);
  
  	/* first communication with embedded */
  	err = mixart_first_init(mgr);
          if (err < 0) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
532
533
  		dev_err(&mgr->pci->dev, "miXart could not be set up
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
538
  		return err;
  	}
  
         	/* create devices and mixer in accordance with HW options*/
          for (card_index = 0; card_index < mgr->num_cards; card_index++) {
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
539
  		struct snd_mixart *chip = mgr->chip[card_index];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
546
547
548
549
550
  
  		if ((err = snd_mixart_create_pcm(chip)) < 0)
  			return err;
  
  		if (card_index == 0) {
  			if ((err = snd_mixart_create_mixer(chip->mgr)) < 0)
  	        		return err;
  		}
  
  		if ((err = snd_card_register(chip->card)) < 0)
  			return err;
395d9dd5d   Peter Senna Tschudin   sound: Remove unn...
551
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552

6414e35de   Takashi Iwai   ALSA: mixart: Use...
553
554
555
  	dev_dbg(&mgr->pci->dev,
  		"miXart firmware downloaded and successfully set up
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
  
  	return 0;
  }
67b48b880   Takashi Iwai   [ALSA] Remove xxx...
559
  int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
564
565
566
567
568
569
570
571
  {
  	static char *fw_files[3] = {
  		"miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
  	};
  	char path[32];
  
  	const struct firmware *fw_entry;
  	int i, err;
  
  	for (i = 0; i < 3; i++) {
  		sprintf(path, "mixart/%s", fw_files[i]);
  		if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
6414e35de   Takashi Iwai   ALSA: mixart: Use...
572
573
574
  			dev_err(&mgr->pci->dev,
  				"miXart: can't load firmware %s
  ", path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
583
584
585
  			return -ENOENT;
  		}
  		/* fake hwdep dsp record */
  		err = mixart_dsp_load(mgr, i, fw_entry);
  		release_firmware(fw_entry);
  		if (err < 0)
  			return err;
  		mgr->dsp_loaded |= 1 << i;
  	}
  	return 0;
  }
7e0af29d6   Clemens Ladisch   [ALSA] add MODULE...
586
587
588
  MODULE_FIRMWARE("mixart/miXart8.xlx");
  MODULE_FIRMWARE("mixart/miXart8.elf");
  MODULE_FIRMWARE("mixart/miXart8AES.xlx");