Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/pci/mixart/mixart_hwdep.c
10820 views
1
/*
2
* Driver for Digigram miXart soundcards
3
*
4
* DSP firmware management
5
*
6
* Copyright (c) 2003 by Digigram <[email protected]>
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 <linux/interrupt.h>
24
#include <linux/pci.h>
25
#include <linux/firmware.h>
26
#include <linux/vmalloc.h>
27
#include <linux/slab.h>
28
#include <asm/io.h>
29
#include <sound/core.h>
30
#include "mixart.h"
31
#include "mixart_mixer.h"
32
#include "mixart_core.h"
33
#include "mixart_hwdep.h"
34
35
36
/**
37
* wait for a value on a peudo register, exit with a timeout
38
*
39
* @param mgr pointer to miXart manager structure
40
* @param offset unsigned pseudo_register base + offset of value
41
* @param value value
42
* @param timeout timeout in centisenconds
43
*/
44
static int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr,
45
u32 offset, int is_egal,
46
u32 value, unsigned long timeout)
47
{
48
unsigned long end_time = jiffies + (timeout * HZ / 100);
49
u32 read;
50
51
do { /* we may take too long time in this loop.
52
* so give controls back to kernel if needed.
53
*/
54
cond_resched();
55
56
read = readl_be( MIXART_MEM( mgr, offset ));
57
if(is_egal) {
58
if(read == value) return 0;
59
}
60
else { /* wait for different value */
61
if(read != value) return 0;
62
}
63
} while ( time_after_eq(end_time, jiffies) );
64
65
return -EBUSY;
66
}
67
68
69
/*
70
structures needed to upload elf code packets
71
*/
72
struct snd_mixart_elf32_ehdr {
73
u8 e_ident[16];
74
u16 e_type;
75
u16 e_machine;
76
u32 e_version;
77
u32 e_entry;
78
u32 e_phoff;
79
u32 e_shoff;
80
u32 e_flags;
81
u16 e_ehsize;
82
u16 e_phentsize;
83
u16 e_phnum;
84
u16 e_shentsize;
85
u16 e_shnum;
86
u16 e_shstrndx;
87
};
88
89
struct snd_mixart_elf32_phdr {
90
u32 p_type;
91
u32 p_offset;
92
u32 p_vaddr;
93
u32 p_paddr;
94
u32 p_filesz;
95
u32 p_memsz;
96
u32 p_flags;
97
u32 p_align;
98
};
99
100
static int mixart_load_elf(struct mixart_mgr *mgr, const struct firmware *dsp )
101
{
102
char elf32_magic_number[4] = {0x7f,'E','L','F'};
103
struct snd_mixart_elf32_ehdr *elf_header;
104
int i;
105
106
elf_header = (struct snd_mixart_elf32_ehdr *)dsp->data;
107
for( i=0; i<4; i++ )
108
if ( elf32_magic_number[i] != elf_header->e_ident[i] )
109
return -EINVAL;
110
111
if( elf_header->e_phoff != 0 ) {
112
struct snd_mixart_elf32_phdr elf_programheader;
113
114
for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {
115
u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));
116
117
memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );
118
119
if(elf_programheader.p_type != 0) {
120
if( elf_programheader.p_filesz != 0 ) {
121
memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
122
dsp->data + be32_to_cpu( elf_programheader.p_offset ),
123
be32_to_cpu( elf_programheader.p_filesz ));
124
}
125
}
126
}
127
}
128
return 0;
129
}
130
131
/*
132
* get basic information and init miXart
133
*/
134
135
/* audio IDs for request to the board */
136
#define MIXART_FIRST_ANA_AUDIO_ID 0
137
#define MIXART_FIRST_DIG_AUDIO_ID 8
138
139
static int mixart_enum_connectors(struct mixart_mgr *mgr)
140
{
141
u32 k;
142
int err;
143
struct mixart_msg request;
144
struct mixart_enum_connector_resp *connector;
145
struct mixart_audio_info_req *audio_info_req;
146
struct mixart_audio_info_resp *audio_info;
147
148
connector = kmalloc(sizeof(*connector), GFP_KERNEL);
149
audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);
150
audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);
151
if (! connector || ! audio_info_req || ! audio_info) {
152
err = -ENOMEM;
153
goto __error;
154
}
155
156
audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
157
audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
158
audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
159
160
request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
161
request.uid = (struct mixart_uid){0,0}; /* board num = 0 */
162
request.data = NULL;
163
request.size = 0;
164
165
err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
166
if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
167
snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
168
err = -EINVAL;
169
goto __error;
170
}
171
172
for(k=0; k < connector->uid_count; k++) {
173
struct mixart_pipe *pipe;
174
175
if(k < MIXART_FIRST_DIG_AUDIO_ID) {
176
pipe = &mgr->chip[k/2]->pipe_out_ana;
177
} else {
178
pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
179
}
180
if(k & 1) {
181
pipe->uid_right_connector = connector->uid[k]; /* odd */
182
} else {
183
pipe->uid_left_connector = connector->uid[k]; /* even */
184
}
185
186
/* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
187
188
/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
189
request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
190
request.uid = connector->uid[k];
191
request.data = audio_info_req;
192
request.size = sizeof(*audio_info_req);
193
194
err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
195
if( err < 0 ) {
196
snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
197
goto __error;
198
}
199
/*snd_printk(KERN_DEBUG "play analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
200
}
201
202
request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
203
request.uid = (struct mixart_uid){0,0}; /* board num = 0 */
204
request.data = NULL;
205
request.size = 0;
206
207
err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
208
if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
209
snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
210
err = -EINVAL;
211
goto __error;
212
}
213
214
for(k=0; k < connector->uid_count; k++) {
215
struct mixart_pipe *pipe;
216
217
if(k < MIXART_FIRST_DIG_AUDIO_ID) {
218
pipe = &mgr->chip[k/2]->pipe_in_ana;
219
} else {
220
pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
221
}
222
if(k & 1) {
223
pipe->uid_right_connector = connector->uid[k]; /* odd */
224
} else {
225
pipe->uid_left_connector = connector->uid[k]; /* even */
226
}
227
228
/* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
229
230
/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
231
request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
232
request.uid = connector->uid[k];
233
request.data = audio_info_req;
234
request.size = sizeof(*audio_info_req);
235
236
err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
237
if( err < 0 ) {
238
snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
239
goto __error;
240
}
241
/*snd_printk(KERN_DEBUG "rec analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
242
}
243
err = 0;
244
245
__error:
246
kfree(connector);
247
kfree(audio_info_req);
248
kfree(audio_info);
249
250
return err;
251
}
252
253
static int mixart_enum_physio(struct mixart_mgr *mgr)
254
{
255
u32 k;
256
int err;
257
struct mixart_msg request;
258
struct mixart_uid get_console_mgr;
259
struct mixart_return_uid console_mgr;
260
struct mixart_uid_enumeration phys_io;
261
262
/* get the uid for the console manager */
263
get_console_mgr.object_id = 0;
264
get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */
265
266
request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
267
request.uid = get_console_mgr;
268
request.data = &get_console_mgr;
269
request.size = sizeof(get_console_mgr);
270
271
err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
272
273
if( (err < 0) || (console_mgr.error_code != 0) ) {
274
snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code);
275
return -EINVAL;
276
}
277
278
/* used later for clock issues ! */
279
mgr->uid_console_manager = console_mgr.uid;
280
281
request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
282
request.uid = (struct mixart_uid){0,0};
283
request.data = &console_mgr.uid;
284
request.size = sizeof(console_mgr.uid);
285
286
err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
287
if( (err < 0) || ( phys_io.error_code != 0 ) ) {
288
snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code );
289
return -EINVAL;
290
}
291
292
/* min 2 phys io per card (analog in + analog out) */
293
if (phys_io.nb_uid < MIXART_MAX_CARDS * 2)
294
return -EINVAL;
295
296
for(k=0; k<mgr->num_cards; k++) {
297
mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
298
mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k];
299
}
300
301
return 0;
302
}
303
304
305
static int mixart_first_init(struct mixart_mgr *mgr)
306
{
307
u32 k;
308
int err;
309
struct mixart_msg request;
310
311
if((err = mixart_enum_connectors(mgr)) < 0) return err;
312
313
if((err = mixart_enum_physio(mgr)) < 0) return err;
314
315
/* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */
316
/* though why not here */
317
request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
318
request.uid = (struct mixart_uid){0,0};
319
request.data = NULL;
320
request.size = 0;
321
/* this command has no data. response is a 32 bit status */
322
err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
323
if( (err < 0) || (k != 0) ) {
324
snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
325
return err == 0 ? -EINVAL : err;
326
}
327
328
return 0;
329
}
330
331
332
/* firmware base addresses (when hard coded) */
333
#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS 0x00600000
334
335
static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmware *dsp)
336
{
337
int err, card_index;
338
u32 status_xilinx, status_elf, status_daught;
339
u32 val;
340
341
/* read motherboard xilinx status */
342
status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
343
/* read elf status */
344
status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
345
/* read daughterboard xilinx status */
346
status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
347
348
/* motherboard xilinx status 5 will say that the board is performing a reset */
349
if (status_xilinx == 5) {
350
snd_printk(KERN_ERR "miXart is resetting !\n");
351
return -EAGAIN; /* try again later */
352
}
353
354
switch (index) {
355
case MIXART_MOTHERBOARD_XLX_INDEX:
356
357
/* xilinx already loaded ? */
358
if (status_xilinx == 4) {
359
snd_printk(KERN_DEBUG "xilinx is already loaded !\n");
360
return 0;
361
}
362
/* the status should be 0 == "idle" */
363
if (status_xilinx != 0) {
364
snd_printk(KERN_ERR "xilinx load error ! status = %d\n",
365
status_xilinx);
366
return -EIO; /* modprob -r may help ? */
367
}
368
369
/* check xilinx validity */
370
if (((u32*)(dsp->data))[0] == 0xffffffff)
371
return -EINVAL;
372
if (dsp->size % 4)
373
return -EINVAL;
374
375
/* set xilinx status to copying */
376
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
377
378
/* setup xilinx base address */
379
writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
380
/* setup code size for xilinx file */
381
writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
382
383
/* copy xilinx code */
384
memcpy_toio( MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS), dsp->data, dsp->size);
385
386
/* set xilinx status to copy finished */
387
writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
388
389
/* return, because no further processing needed */
390
return 0;
391
392
case MIXART_MOTHERBOARD_ELF_INDEX:
393
394
if (status_elf == 4) {
395
snd_printk(KERN_DEBUG "elf file already loaded !\n");
396
return 0;
397
}
398
399
/* the status should be 0 == "idle" */
400
if (status_elf != 0) {
401
snd_printk(KERN_ERR "elf load error ! status = %d\n",
402
status_elf);
403
return -EIO; /* modprob -r may help ? */
404
}
405
406
/* wait for xilinx status == 4 */
407
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
408
if (err < 0) {
409
snd_printk(KERN_ERR "xilinx was not loaded or "
410
"could not be started\n");
411
return err;
412
}
413
414
/* init some data on the card */
415
writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */
416
writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* reset pointer to flow table on miXart */
417
418
/* set elf status to copying */
419
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
420
421
/* process the copying of the elf packets */
422
err = mixart_load_elf( mgr, dsp );
423
if (err < 0) return err;
424
425
/* set elf status to copy finished */
426
writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
427
428
/* wait for elf status == 4 */
429
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
430
if (err < 0) {
431
snd_printk(KERN_ERR "elf could not be started\n");
432
return err;
433
}
434
435
/* miXart waits at this point on the pointer to the flow table */
436
writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */
437
438
return 0; /* return, another xilinx file has to be loaded before */
439
440
case MIXART_AESEBUBOARD_XLX_INDEX:
441
default:
442
443
/* elf and xilinx should be loaded */
444
if (status_elf != 4 || status_xilinx != 4) {
445
printk(KERN_ERR "xilinx or elf not "
446
"successfully loaded\n");
447
return -EIO; /* modprob -r may help ? */
448
}
449
450
/* wait for daughter detection != 0 */
451
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
452
if (err < 0) {
453
snd_printk(KERN_ERR "error starting elf file\n");
454
return err;
455
}
456
457
/* the board type can now be retrieved */
458
mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
459
460
if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
461
break; /* no daughter board; the file does not have to be loaded, continue after the switch */
462
463
/* only if aesebu daughter board presence (elf code must run) */
464
if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
465
return -EINVAL;
466
467
/* daughter should be idle */
468
if (status_daught != 0) {
469
printk(KERN_ERR "daughter load error ! status = %d\n",
470
status_daught);
471
return -EIO; /* modprob -r may help ? */
472
}
473
474
/* check daughterboard xilinx validity */
475
if (((u32*)(dsp->data))[0] == 0xffffffff)
476
return -EINVAL;
477
if (dsp->size % 4)
478
return -EINVAL;
479
480
/* inform mixart about the size of the file */
481
writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
482
483
/* set daughterboard status to 1 */
484
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
485
486
/* wait for status == 2 */
487
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
488
if (err < 0) {
489
snd_printk(KERN_ERR "daughter board load error\n");
490
return err;
491
}
492
493
/* get the address where to write the file */
494
val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
495
if (!val)
496
return -EINVAL;
497
498
/* copy daughterboard xilinx code */
499
memcpy_toio( MIXART_MEM( mgr, val), dsp->data, dsp->size);
500
501
/* set daughterboard status to 4 */
502
writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
503
504
/* continue with init */
505
break;
506
} /* end of switch file index*/
507
508
/* wait for daughter status == 3 */
509
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
510
if (err < 0) {
511
snd_printk(KERN_ERR
512
"daughter board could not be initialised\n");
513
return err;
514
}
515
516
/* init mailbox (communication with embedded) */
517
snd_mixart_init_mailbox(mgr);
518
519
/* first communication with embedded */
520
err = mixart_first_init(mgr);
521
if (err < 0) {
522
snd_printk(KERN_ERR "miXart could not be set up\n");
523
return err;
524
}
525
526
/* create devices and mixer in accordance with HW options*/
527
for (card_index = 0; card_index < mgr->num_cards; card_index++) {
528
struct snd_mixart *chip = mgr->chip[card_index];
529
530
if ((err = snd_mixart_create_pcm(chip)) < 0)
531
return err;
532
533
if (card_index == 0) {
534
if ((err = snd_mixart_create_mixer(chip->mgr)) < 0)
535
return err;
536
}
537
538
if ((err = snd_card_register(chip->card)) < 0)
539
return err;
540
};
541
542
snd_printdd("miXart firmware downloaded and successfully set up\n");
543
544
return 0;
545
}
546
547
548
#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
549
#if !defined(CONFIG_USE_MIXARTLOADER) && !defined(CONFIG_SND_MIXART) /* built-in kernel */
550
#define SND_MIXART_FW_LOADER /* use the standard firmware loader */
551
#endif
552
#endif
553
554
#ifdef SND_MIXART_FW_LOADER
555
556
int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
557
{
558
static char *fw_files[3] = {
559
"miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
560
};
561
char path[32];
562
563
const struct firmware *fw_entry;
564
int i, err;
565
566
for (i = 0; i < 3; i++) {
567
sprintf(path, "mixart/%s", fw_files[i]);
568
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
569
snd_printk(KERN_ERR "miXart: can't load firmware %s\n", path);
570
return -ENOENT;
571
}
572
/* fake hwdep dsp record */
573
err = mixart_dsp_load(mgr, i, fw_entry);
574
release_firmware(fw_entry);
575
if (err < 0)
576
return err;
577
mgr->dsp_loaded |= 1 << i;
578
}
579
return 0;
580
}
581
582
MODULE_FIRMWARE("mixart/miXart8.xlx");
583
MODULE_FIRMWARE("mixart/miXart8.elf");
584
MODULE_FIRMWARE("mixart/miXart8AES.xlx");
585
586
#else /* old style firmware loading */
587
588
/* miXart hwdep interface id string */
589
#define SND_MIXART_HWDEP_ID "miXart Loader"
590
591
static int mixart_hwdep_dsp_status(struct snd_hwdep *hw,
592
struct snd_hwdep_dsp_status *info)
593
{
594
struct mixart_mgr *mgr = hw->private_data;
595
596
strcpy(info->id, "miXart");
597
info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX;
598
599
if (mgr->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX))
600
info->chip_ready = 1;
601
602
info->version = MIXART_DRIVER_VERSION;
603
return 0;
604
}
605
606
static int mixart_hwdep_dsp_load(struct snd_hwdep *hw,
607
struct snd_hwdep_dsp_image *dsp)
608
{
609
struct mixart_mgr* mgr = hw->private_data;
610
struct firmware fw;
611
int err;
612
613
fw.size = dsp->length;
614
fw.data = vmalloc(dsp->length);
615
if (! fw.data) {
616
snd_printk(KERN_ERR "miXart: cannot allocate image size %d\n",
617
(int)dsp->length);
618
return -ENOMEM;
619
}
620
if (copy_from_user((void *) fw.data, dsp->image, dsp->length)) {
621
vfree(fw.data);
622
return -EFAULT;
623
}
624
err = mixart_dsp_load(mgr, dsp->index, &fw);
625
vfree(fw.data);
626
if (err < 0)
627
return err;
628
mgr->dsp_loaded |= 1 << dsp->index;
629
return err;
630
}
631
632
int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
633
{
634
int err;
635
struct snd_hwdep *hw;
636
637
/* only create hwdep interface for first cardX (see "index" module parameter)*/
638
if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0)
639
return err;
640
641
hw->iface = SNDRV_HWDEP_IFACE_MIXART;
642
hw->private_data = mgr;
643
hw->ops.dsp_status = mixart_hwdep_dsp_status;
644
hw->ops.dsp_load = mixart_hwdep_dsp_load;
645
hw->exclusive = 1;
646
sprintf(hw->name, SND_MIXART_HWDEP_ID);
647
mgr->dsp_loaded = 0;
648
649
return snd_card_register(mgr->chip[0]->card);
650
}
651
652
#endif /* SND_MIXART_FW_LOADER */
653
654