1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Driver for Digigram VX soundcards |
4 | * |
5 | * Hardware core part |
6 | * |
7 | * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> |
8 | */ |
9 | |
10 | #include <linux/delay.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/init.h> |
14 | #include <linux/device.h> |
15 | #include <linux/firmware.h> |
16 | #include <linux/module.h> |
17 | #include <linux/io.h> |
18 | #include <sound/core.h> |
19 | #include <sound/pcm.h> |
20 | #include <sound/asoundef.h> |
21 | #include <sound/info.h> |
22 | #include <sound/vx_core.h> |
23 | #include "vx_cmd.h" |
24 | |
25 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>" ); |
26 | MODULE_DESCRIPTION("Common routines for Digigram VX drivers" ); |
27 | MODULE_LICENSE("GPL" ); |
28 | |
29 | |
30 | /* |
31 | * vx_check_reg_bit - wait for the specified bit is set/reset on a register |
32 | * @reg: register to check |
33 | * @mask: bit mask |
34 | * @bit: resultant bit to be checked |
35 | * @time: time-out of loop in msec |
36 | * |
37 | * returns zero if a bit matches, or a negative error code. |
38 | */ |
39 | int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int time) |
40 | { |
41 | unsigned long end_time = jiffies + (time * HZ + 999) / 1000; |
42 | static const char * const reg_names[VX_REG_MAX] = { |
43 | "ICR" , "CVR" , "ISR" , "IVR" , "RXH" , "RXM" , "RXL" , |
44 | "DMA" , "CDSP" , "RFREQ" , "RUER/V2" , "DATA" , "MEMIRQ" , |
45 | "ACQ" , "BIT0" , "BIT1" , "MIC0" , "MIC1" , "MIC2" , |
46 | "MIC3" , "INTCSR" , "CNTRL" , "GPIOC" , |
47 | "LOFREQ" , "HIFREQ" , "CSUER" , "RUER" |
48 | }; |
49 | |
50 | do { |
51 | if ((snd_vx_inb(chip, reg) & mask) == bit) |
52 | return 0; |
53 | //msleep(10); |
54 | } while (time_after_eq(end_time, jiffies)); |
55 | snd_printd(KERN_DEBUG "vx_check_reg_bit: timeout, reg=%s, mask=0x%x, val=0x%x\n" , reg_names[reg], mask, snd_vx_inb(chip, reg)); |
56 | return -EIO; |
57 | } |
58 | |
59 | EXPORT_SYMBOL(snd_vx_check_reg_bit); |
60 | |
61 | /* |
62 | * vx_send_irq_dsp - set command irq bit |
63 | * @num: the requested IRQ type, IRQ_XXX |
64 | * |
65 | * this triggers the specified IRQ request |
66 | * returns 0 if successful, or a negative error code. |
67 | * |
68 | */ |
69 | static int vx_send_irq_dsp(struct vx_core *chip, int num) |
70 | { |
71 | int nirq; |
72 | |
73 | /* wait for Hc = 0 */ |
74 | if (snd_vx_check_reg_bit(chip, VX_CVR, CVR_HC, 0, 200) < 0) |
75 | return -EIO; |
76 | |
77 | nirq = num; |
78 | if (vx_has_new_dsp(chip)) |
79 | nirq += VXP_IRQ_OFFSET; |
80 | vx_outb(chip, CVR, (nirq >> 1) | CVR_HC); |
81 | return 0; |
82 | } |
83 | |
84 | |
85 | /* |
86 | * vx_reset_chk - reset CHK bit on ISR |
87 | * |
88 | * returns 0 if successful, or a negative error code. |
89 | */ |
90 | static int vx_reset_chk(struct vx_core *chip) |
91 | { |
92 | /* Reset irq CHK */ |
93 | if (vx_send_irq_dsp(chip, IRQ_RESET_CHK) < 0) |
94 | return -EIO; |
95 | /* Wait until CHK = 0 */ |
96 | if (vx_check_isr(chip, ISR_CHK, 0, 200) < 0) |
97 | return -EIO; |
98 | return 0; |
99 | } |
100 | |
101 | /* |
102 | * vx_transfer_end - terminate message transfer |
103 | * @cmd: IRQ message to send (IRQ_MESS_XXX_END) |
104 | * |
105 | * returns 0 if successful, or a negative error code. |
106 | * the error code can be VX-specific, retrieved via vx_get_error(). |
107 | * NB: call with mutex held! |
108 | */ |
109 | static int vx_transfer_end(struct vx_core *chip, int cmd) |
110 | { |
111 | int err; |
112 | |
113 | err = vx_reset_chk(chip); |
114 | if (err < 0) |
115 | return err; |
116 | |
117 | /* irq MESS_READ/WRITE_END */ |
118 | err = vx_send_irq_dsp(chip, num: cmd); |
119 | if (err < 0) |
120 | return err; |
121 | |
122 | /* Wait CHK = 1 */ |
123 | err = vx_wait_isr_bit(chip, ISR_CHK); |
124 | if (err < 0) |
125 | return err; |
126 | |
127 | /* If error, Read RX */ |
128 | err = vx_inb(chip, ISR); |
129 | if (err & ISR_ERR) { |
130 | err = vx_wait_for_rx_full(chip); |
131 | if (err < 0) { |
132 | snd_printd(KERN_DEBUG "transfer_end: error in rx_full\n" ); |
133 | return err; |
134 | } |
135 | err = vx_inb(chip, RXH) << 16; |
136 | err |= vx_inb(chip, RXM) << 8; |
137 | err |= vx_inb(chip, RXL); |
138 | snd_printd(KERN_DEBUG "transfer_end: error = 0x%x\n" , err); |
139 | return -(VX_ERR_MASK | err); |
140 | } |
141 | return 0; |
142 | } |
143 | |
144 | /* |
145 | * vx_read_status - return the status rmh |
146 | * @rmh: rmh record to store the status |
147 | * |
148 | * returns 0 if successful, or a negative error code. |
149 | * the error code can be VX-specific, retrieved via vx_get_error(). |
150 | * NB: call with mutex held! |
151 | */ |
152 | static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh) |
153 | { |
154 | int i, err, val, size; |
155 | |
156 | /* no read necessary? */ |
157 | if (rmh->DspStat == RMH_SSIZE_FIXED && rmh->LgStat == 0) |
158 | return 0; |
159 | |
160 | /* Wait for RX full (with timeout protection) |
161 | * The first word of status is in RX |
162 | */ |
163 | err = vx_wait_for_rx_full(chip); |
164 | if (err < 0) |
165 | return err; |
166 | |
167 | /* Read RX */ |
168 | val = vx_inb(chip, RXH) << 16; |
169 | val |= vx_inb(chip, RXM) << 8; |
170 | val |= vx_inb(chip, RXL); |
171 | |
172 | /* If status given by DSP, let's decode its size */ |
173 | switch (rmh->DspStat) { |
174 | case RMH_SSIZE_ARG: |
175 | size = val & 0xff; |
176 | rmh->Stat[0] = val & 0xffff00; |
177 | rmh->LgStat = size + 1; |
178 | break; |
179 | case RMH_SSIZE_MASK: |
180 | /* Let's count the arg numbers from a mask */ |
181 | rmh->Stat[0] = val; |
182 | size = 0; |
183 | while (val) { |
184 | if (val & 0x01) |
185 | size++; |
186 | val >>= 1; |
187 | } |
188 | rmh->LgStat = size + 1; |
189 | break; |
190 | default: |
191 | /* else retrieve the status length given by the driver */ |
192 | size = rmh->LgStat; |
193 | rmh->Stat[0] = val; /* Val is the status 1st word */ |
194 | size--; /* hence adjust remaining length */ |
195 | break; |
196 | } |
197 | |
198 | if (size < 1) |
199 | return 0; |
200 | if (snd_BUG_ON(size >= SIZE_MAX_STATUS)) |
201 | return -EINVAL; |
202 | |
203 | for (i = 1; i <= size; i++) { |
204 | /* trigger an irq MESS_WRITE_NEXT */ |
205 | err = vx_send_irq_dsp(chip, IRQ_MESS_WRITE_NEXT); |
206 | if (err < 0) |
207 | return err; |
208 | /* Wait for RX full (with timeout protection) */ |
209 | err = vx_wait_for_rx_full(chip); |
210 | if (err < 0) |
211 | return err; |
212 | rmh->Stat[i] = vx_inb(chip, RXH) << 16; |
213 | rmh->Stat[i] |= vx_inb(chip, RXM) << 8; |
214 | rmh->Stat[i] |= vx_inb(chip, RXL); |
215 | } |
216 | |
217 | return vx_transfer_end(chip, IRQ_MESS_WRITE_END); |
218 | } |
219 | |
220 | |
221 | #define MASK_MORE_THAN_1_WORD_COMMAND 0x00008000 |
222 | #define MASK_1_WORD_COMMAND 0x00ff7fff |
223 | |
224 | /* |
225 | * vx_send_msg_nolock - send a DSP message and read back the status |
226 | * @rmh: the rmh record to send and receive |
227 | * |
228 | * returns 0 if successful, or a negative error code. |
229 | * the error code can be VX-specific, retrieved via vx_get_error(). |
230 | * |
231 | * this function doesn't call mutex lock at all. |
232 | */ |
233 | int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) |
234 | { |
235 | int i, err; |
236 | |
237 | if (chip->chip_status & VX_STAT_IS_STALE) |
238 | return -EBUSY; |
239 | |
240 | err = vx_reset_chk(chip); |
241 | if (err < 0) { |
242 | snd_printd(KERN_DEBUG "vx_send_msg: vx_reset_chk error\n" ); |
243 | return err; |
244 | } |
245 | |
246 | #if 0 |
247 | printk(KERN_DEBUG "rmh: cmd = 0x%06x, length = %d, stype = %d\n" , |
248 | rmh->Cmd[0], rmh->LgCmd, rmh->DspStat); |
249 | if (rmh->LgCmd > 1) { |
250 | printk(KERN_DEBUG " " ); |
251 | for (i = 1; i < rmh->LgCmd; i++) |
252 | printk(KERN_CONT "0x%06x " , rmh->Cmd[i]); |
253 | printk(KERN_CONT "\n" ); |
254 | } |
255 | #endif |
256 | /* Check bit M is set according to length of the command */ |
257 | if (rmh->LgCmd > 1) |
258 | rmh->Cmd[0] |= MASK_MORE_THAN_1_WORD_COMMAND; |
259 | else |
260 | rmh->Cmd[0] &= MASK_1_WORD_COMMAND; |
261 | |
262 | /* Wait for TX empty */ |
263 | err = vx_wait_isr_bit(chip, ISR_TX_EMPTY); |
264 | if (err < 0) { |
265 | snd_printd(KERN_DEBUG "vx_send_msg: wait tx empty error\n" ); |
266 | return err; |
267 | } |
268 | |
269 | /* Write Cmd[0] */ |
270 | vx_outb(chip, TXH, (rmh->Cmd[0] >> 16) & 0xff); |
271 | vx_outb(chip, TXM, (rmh->Cmd[0] >> 8) & 0xff); |
272 | vx_outb(chip, TXL, rmh->Cmd[0] & 0xff); |
273 | |
274 | /* Trigger irq MESSAGE */ |
275 | err = vx_send_irq_dsp(chip, IRQ_MESSAGE); |
276 | if (err < 0) { |
277 | snd_printd(KERN_DEBUG "vx_send_msg: send IRQ_MESSAGE error\n" ); |
278 | return err; |
279 | } |
280 | |
281 | /* Wait for CHK = 1 */ |
282 | err = vx_wait_isr_bit(chip, ISR_CHK); |
283 | if (err < 0) |
284 | return err; |
285 | |
286 | /* If error, get error value from RX */ |
287 | if (vx_inb(chip, ISR) & ISR_ERR) { |
288 | err = vx_wait_for_rx_full(chip); |
289 | if (err < 0) { |
290 | snd_printd(KERN_DEBUG "vx_send_msg: rx_full read error\n" ); |
291 | return err; |
292 | } |
293 | err = vx_inb(chip, RXH) << 16; |
294 | err |= vx_inb(chip, RXM) << 8; |
295 | err |= vx_inb(chip, RXL); |
296 | snd_printd(KERN_DEBUG "msg got error = 0x%x at cmd[0]\n" , err); |
297 | err = -(VX_ERR_MASK | err); |
298 | return err; |
299 | } |
300 | |
301 | /* Send the other words */ |
302 | if (rmh->LgCmd > 1) { |
303 | for (i = 1; i < rmh->LgCmd; i++) { |
304 | /* Wait for TX ready */ |
305 | err = vx_wait_isr_bit(chip, ISR_TX_READY); |
306 | if (err < 0) { |
307 | snd_printd(KERN_DEBUG "vx_send_msg: tx_ready error\n" ); |
308 | return err; |
309 | } |
310 | |
311 | /* Write Cmd[i] */ |
312 | vx_outb(chip, TXH, (rmh->Cmd[i] >> 16) & 0xff); |
313 | vx_outb(chip, TXM, (rmh->Cmd[i] >> 8) & 0xff); |
314 | vx_outb(chip, TXL, rmh->Cmd[i] & 0xff); |
315 | |
316 | /* Trigger irq MESS_READ_NEXT */ |
317 | err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT); |
318 | if (err < 0) { |
319 | snd_printd(KERN_DEBUG "vx_send_msg: IRQ_READ_NEXT error\n" ); |
320 | return err; |
321 | } |
322 | } |
323 | /* Wait for TX empty */ |
324 | err = vx_wait_isr_bit(chip, ISR_TX_READY); |
325 | if (err < 0) { |
326 | snd_printd(KERN_DEBUG "vx_send_msg: TX_READY error\n" ); |
327 | return err; |
328 | } |
329 | /* End of transfer */ |
330 | err = vx_transfer_end(chip, IRQ_MESS_READ_END); |
331 | if (err < 0) |
332 | return err; |
333 | } |
334 | |
335 | return vx_read_status(chip, rmh); |
336 | } |
337 | |
338 | |
339 | /* |
340 | * vx_send_msg - send a DSP message with mutex |
341 | * @rmh: the rmh record to send and receive |
342 | * |
343 | * returns 0 if successful, or a negative error code. |
344 | * see vx_send_msg_nolock(). |
345 | */ |
346 | int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh) |
347 | { |
348 | int err; |
349 | |
350 | mutex_lock(&chip->lock); |
351 | err = vx_send_msg_nolock(chip, rmh); |
352 | mutex_unlock(lock: &chip->lock); |
353 | return err; |
354 | } |
355 | |
356 | |
357 | /* |
358 | * vx_send_rih_nolock - send an RIH to xilinx |
359 | * @cmd: the command to send |
360 | * |
361 | * returns 0 if successful, or a negative error code. |
362 | * the error code can be VX-specific, retrieved via vx_get_error(). |
363 | * |
364 | * this function doesn't call mutex at all. |
365 | * |
366 | * unlike RMH, no command is sent to DSP. |
367 | */ |
368 | int vx_send_rih_nolock(struct vx_core *chip, int cmd) |
369 | { |
370 | int err; |
371 | |
372 | if (chip->chip_status & VX_STAT_IS_STALE) |
373 | return -EBUSY; |
374 | |
375 | #if 0 |
376 | printk(KERN_DEBUG "send_rih: cmd = 0x%x\n" , cmd); |
377 | #endif |
378 | err = vx_reset_chk(chip); |
379 | if (err < 0) |
380 | return err; |
381 | /* send the IRQ */ |
382 | err = vx_send_irq_dsp(chip, num: cmd); |
383 | if (err < 0) |
384 | return err; |
385 | /* Wait CHK = 1 */ |
386 | err = vx_wait_isr_bit(chip, ISR_CHK); |
387 | if (err < 0) |
388 | return err; |
389 | /* If error, read RX */ |
390 | if (vx_inb(chip, ISR) & ISR_ERR) { |
391 | err = vx_wait_for_rx_full(chip); |
392 | if (err < 0) |
393 | return err; |
394 | err = vx_inb(chip, RXH) << 16; |
395 | err |= vx_inb(chip, RXM) << 8; |
396 | err |= vx_inb(chip, RXL); |
397 | return -(VX_ERR_MASK | err); |
398 | } |
399 | return 0; |
400 | } |
401 | |
402 | |
403 | /* |
404 | * vx_send_rih - send an RIH with mutex |
405 | * @cmd: the command to send |
406 | * |
407 | * see vx_send_rih_nolock(). |
408 | */ |
409 | int vx_send_rih(struct vx_core *chip, int cmd) |
410 | { |
411 | int err; |
412 | |
413 | mutex_lock(&chip->lock); |
414 | err = vx_send_rih_nolock(chip, cmd); |
415 | mutex_unlock(lock: &chip->lock); |
416 | return err; |
417 | } |
418 | |
419 | #define END_OF_RESET_WAIT_TIME 500 /* us */ |
420 | |
421 | /** |
422 | * snd_vx_load_boot_image - boot up the xilinx interface |
423 | * @chip: VX core instance |
424 | * @boot: the boot record to load |
425 | */ |
426 | int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot) |
427 | { |
428 | unsigned int i; |
429 | int no_fillup = vx_has_new_dsp(chip); |
430 | |
431 | /* check the length of boot image */ |
432 | if (boot->size <= 0) |
433 | return -EINVAL; |
434 | if (boot->size % 3) |
435 | return -EINVAL; |
436 | #if 0 |
437 | { |
438 | /* more strict check */ |
439 | unsigned int c = ((u32)boot->data[0] << 16) | ((u32)boot->data[1] << 8) | boot->data[2]; |
440 | if (boot->size != (c + 2) * 3) |
441 | return -EINVAL; |
442 | } |
443 | #endif |
444 | |
445 | /* reset dsp */ |
446 | vx_reset_dsp(chip); |
447 | |
448 | udelay(END_OF_RESET_WAIT_TIME); /* another wait? */ |
449 | |
450 | /* download boot strap */ |
451 | for (i = 0; i < 0x600; i += 3) { |
452 | if (i >= boot->size) { |
453 | if (no_fillup) |
454 | break; |
455 | if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { |
456 | snd_printk(KERN_ERR "dsp boot failed at %d\n" , i); |
457 | return -EIO; |
458 | } |
459 | vx_outb(chip, TXH, 0); |
460 | vx_outb(chip, TXM, 0); |
461 | vx_outb(chip, TXL, 0); |
462 | } else { |
463 | const unsigned char *image = boot->data + i; |
464 | if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { |
465 | snd_printk(KERN_ERR "dsp boot failed at %d\n" , i); |
466 | return -EIO; |
467 | } |
468 | vx_outb(chip, TXH, image[0]); |
469 | vx_outb(chip, TXM, image[1]); |
470 | vx_outb(chip, TXL, image[2]); |
471 | } |
472 | } |
473 | return 0; |
474 | } |
475 | |
476 | EXPORT_SYMBOL(snd_vx_load_boot_image); |
477 | |
478 | /* |
479 | * vx_test_irq_src - query the source of interrupts |
480 | * |
481 | * called from irq handler only |
482 | */ |
483 | static int vx_test_irq_src(struct vx_core *chip, unsigned int *ret) |
484 | { |
485 | int err; |
486 | |
487 | vx_init_rmh(rmh: &chip->irq_rmh, cmd: CMD_TEST_IT); |
488 | mutex_lock(&chip->lock); |
489 | err = vx_send_msg_nolock(chip, rmh: &chip->irq_rmh); |
490 | if (err < 0) |
491 | *ret = 0; |
492 | else |
493 | *ret = chip->irq_rmh.Stat[0]; |
494 | mutex_unlock(lock: &chip->lock); |
495 | return err; |
496 | } |
497 | |
498 | |
499 | /* |
500 | * snd_vx_threaded_irq_handler - threaded irq handler |
501 | */ |
502 | irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev) |
503 | { |
504 | struct vx_core *chip = dev; |
505 | unsigned int events; |
506 | |
507 | if (chip->chip_status & VX_STAT_IS_STALE) |
508 | return IRQ_HANDLED; |
509 | |
510 | if (vx_test_irq_src(chip, ret: &events) < 0) |
511 | return IRQ_HANDLED; |
512 | |
513 | #if 0 |
514 | if (events & 0x000800) |
515 | printk(KERN_ERR "DSP Stream underrun ! IRQ events = 0x%x\n" , events); |
516 | #endif |
517 | // printk(KERN_DEBUG "IRQ events = 0x%x\n", events); |
518 | |
519 | /* We must prevent any application using this DSP |
520 | * and block any further request until the application |
521 | * either unregisters or reloads the DSP |
522 | */ |
523 | if (events & FATAL_DSP_ERROR) { |
524 | snd_printk(KERN_ERR "vx_core: fatal DSP error!!\n" ); |
525 | return IRQ_HANDLED; |
526 | } |
527 | |
528 | /* The start on time code conditions are filled (ie the time code |
529 | * received by the board is equal to one of those given to it). |
530 | */ |
531 | if (events & TIME_CODE_EVENT_PENDING) { |
532 | ; /* so far, nothing to do yet */ |
533 | } |
534 | |
535 | /* The frequency has changed on the board (UER mode). */ |
536 | if (events & FREQUENCY_CHANGE_EVENT_PENDING) |
537 | vx_change_frequency(chip); |
538 | |
539 | /* update the pcm streams */ |
540 | vx_pcm_update_intr(chip, events); |
541 | return IRQ_HANDLED; |
542 | } |
543 | EXPORT_SYMBOL(snd_vx_threaded_irq_handler); |
544 | |
545 | /** |
546 | * snd_vx_irq_handler - interrupt handler |
547 | * @irq: irq number |
548 | * @dev: VX core instance |
549 | */ |
550 | irqreturn_t snd_vx_irq_handler(int irq, void *dev) |
551 | { |
552 | struct vx_core *chip = dev; |
553 | |
554 | if (! (chip->chip_status & VX_STAT_CHIP_INIT) || |
555 | (chip->chip_status & VX_STAT_IS_STALE)) |
556 | return IRQ_NONE; |
557 | if (! vx_test_and_ack(chip)) |
558 | return IRQ_WAKE_THREAD; |
559 | return IRQ_NONE; |
560 | } |
561 | |
562 | EXPORT_SYMBOL(snd_vx_irq_handler); |
563 | |
564 | /* |
565 | */ |
566 | static void vx_reset_board(struct vx_core *chip, int cold_reset) |
567 | { |
568 | if (snd_BUG_ON(!chip->ops->reset_board)) |
569 | return; |
570 | |
571 | /* current source, later sync'ed with target */ |
572 | chip->audio_source = VX_AUDIO_SRC_LINE; |
573 | if (cold_reset) { |
574 | chip->audio_source_target = chip->audio_source; |
575 | chip->clock_source = INTERNAL_QUARTZ; |
576 | chip->clock_mode = VX_CLOCK_MODE_AUTO; |
577 | chip->freq = 48000; |
578 | chip->uer_detected = VX_UER_MODE_NOT_PRESENT; |
579 | chip->uer_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; |
580 | } |
581 | |
582 | chip->ops->reset_board(chip, cold_reset); |
583 | |
584 | vx_reset_codec(chip, cold_reset); |
585 | |
586 | vx_set_internal_clock(chip, freq: chip->freq); |
587 | |
588 | /* Reset the DSP */ |
589 | vx_reset_dsp(chip); |
590 | |
591 | if (vx_is_pcmcia(chip)) { |
592 | /* Acknowledge any pending IRQ and reset the MEMIRQ flag. */ |
593 | vx_test_and_ack(chip); |
594 | vx_validate_irq(chip, enable: 1); |
595 | } |
596 | |
597 | /* init CBits */ |
598 | vx_set_iec958_status(chip, bits: chip->uer_bits); |
599 | } |
600 | |
601 | |
602 | /* |
603 | * proc interface |
604 | */ |
605 | |
606 | static void vx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
607 | { |
608 | struct vx_core *chip = entry->private_data; |
609 | static const char * const audio_src_vxp[] = { "Line" , "Mic" , "Digital" }; |
610 | static const char * const audio_src_vx2[] = { "Analog" , "Analog" , "Digital" }; |
611 | static const char * const clock_mode[] = { "Auto" , "Internal" , "External" }; |
612 | static const char * const clock_src[] = { "Internal" , "External" }; |
613 | static const char * const uer_type[] = { "Consumer" , "Professional" , "Not Present" }; |
614 | |
615 | snd_iprintf(buffer, "%s\n" , chip->card->longname); |
616 | snd_iprintf(buffer, "Xilinx Firmware: %s\n" , |
617 | (chip->chip_status & VX_STAT_XILINX_LOADED) ? "Loaded" : "No" ); |
618 | snd_iprintf(buffer, "Device Initialized: %s\n" , |
619 | (chip->chip_status & VX_STAT_DEVICE_INIT) ? "Yes" : "No" ); |
620 | snd_iprintf(buffer, "DSP audio info:" ); |
621 | if (chip->audio_info & VX_AUDIO_INFO_REAL_TIME) |
622 | snd_iprintf(buffer, " realtime" ); |
623 | if (chip->audio_info & VX_AUDIO_INFO_OFFLINE) |
624 | snd_iprintf(buffer, " offline" ); |
625 | if (chip->audio_info & VX_AUDIO_INFO_MPEG1) |
626 | snd_iprintf(buffer, " mpeg1" ); |
627 | if (chip->audio_info & VX_AUDIO_INFO_MPEG2) |
628 | snd_iprintf(buffer, " mpeg2" ); |
629 | if (chip->audio_info & VX_AUDIO_INFO_LINEAR_8) |
630 | snd_iprintf(buffer, " linear8" ); |
631 | if (chip->audio_info & VX_AUDIO_INFO_LINEAR_16) |
632 | snd_iprintf(buffer, " linear16" ); |
633 | if (chip->audio_info & VX_AUDIO_INFO_LINEAR_24) |
634 | snd_iprintf(buffer, " linear24" ); |
635 | snd_iprintf(buffer, "\n" ); |
636 | snd_iprintf(buffer, "Input Source: %s\n" , vx_is_pcmcia(chip) ? |
637 | audio_src_vxp[chip->audio_source] : |
638 | audio_src_vx2[chip->audio_source]); |
639 | snd_iprintf(buffer, "Clock Mode: %s\n" , clock_mode[chip->clock_mode]); |
640 | snd_iprintf(buffer, "Clock Source: %s\n" , clock_src[chip->clock_source]); |
641 | snd_iprintf(buffer, "Frequency: %d\n" , chip->freq); |
642 | snd_iprintf(buffer, "Detected Frequency: %d\n" , chip->freq_detected); |
643 | snd_iprintf(buffer, "Detected UER type: %s\n" , uer_type[chip->uer_detected]); |
644 | snd_iprintf(buffer, "Min/Max/Cur IBL: %d/%d/%d (granularity=%d)\n" , |
645 | chip->ibl.min_size, chip->ibl.max_size, chip->ibl.size, |
646 | chip->ibl.granularity); |
647 | } |
648 | |
649 | static void vx_proc_init(struct vx_core *chip) |
650 | { |
651 | snd_card_ro_proc_new(card: chip->card, name: "vx-status" , private_data: chip, read: vx_proc_read); |
652 | } |
653 | |
654 | |
655 | /** |
656 | * snd_vx_dsp_boot - load the DSP boot |
657 | * @chip: VX core instance |
658 | * @boot: firmware data |
659 | */ |
660 | int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot) |
661 | { |
662 | int err; |
663 | int cold_reset = !(chip->chip_status & VX_STAT_DEVICE_INIT); |
664 | |
665 | vx_reset_board(chip, cold_reset); |
666 | vx_validate_irq(chip, enable: 0); |
667 | |
668 | err = snd_vx_load_boot_image(chip, boot); |
669 | if (err < 0) |
670 | return err; |
671 | msleep(msecs: 10); |
672 | |
673 | return 0; |
674 | } |
675 | |
676 | EXPORT_SYMBOL(snd_vx_dsp_boot); |
677 | |
678 | /** |
679 | * snd_vx_dsp_load - load the DSP image |
680 | * @chip: VX core instance |
681 | * @dsp: firmware data |
682 | */ |
683 | int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp) |
684 | { |
685 | unsigned int i; |
686 | int err; |
687 | unsigned int csum = 0; |
688 | const unsigned char *image, *cptr; |
689 | |
690 | if (dsp->size % 3) |
691 | return -EINVAL; |
692 | |
693 | vx_toggle_dac_mute(chip, mute: 1); |
694 | |
695 | /* Transfert data buffer from PC to DSP */ |
696 | for (i = 0; i < dsp->size; i += 3) { |
697 | image = dsp->data + i; |
698 | /* Wait DSP ready for a new read */ |
699 | err = vx_wait_isr_bit(chip, ISR_TX_EMPTY); |
700 | if (err < 0) { |
701 | printk(KERN_ERR |
702 | "dsp loading error at position %d\n" , i); |
703 | return err; |
704 | } |
705 | cptr = image; |
706 | csum ^= *cptr; |
707 | csum = (csum >> 24) | (csum << 8); |
708 | vx_outb(chip, TXH, *cptr++); |
709 | csum ^= *cptr; |
710 | csum = (csum >> 24) | (csum << 8); |
711 | vx_outb(chip, TXM, *cptr++); |
712 | csum ^= *cptr; |
713 | csum = (csum >> 24) | (csum << 8); |
714 | vx_outb(chip, TXL, *cptr++); |
715 | } |
716 | snd_printdd(KERN_DEBUG "checksum = 0x%08x\n" , csum); |
717 | |
718 | msleep(msecs: 200); |
719 | |
720 | err = vx_wait_isr_bit(chip, ISR_CHK); |
721 | if (err < 0) |
722 | return err; |
723 | |
724 | vx_toggle_dac_mute(chip, mute: 0); |
725 | |
726 | vx_test_and_ack(chip); |
727 | vx_validate_irq(chip, enable: 1); |
728 | |
729 | return 0; |
730 | } |
731 | |
732 | EXPORT_SYMBOL(snd_vx_dsp_load); |
733 | |
734 | #ifdef CONFIG_PM |
735 | /* |
736 | * suspend |
737 | */ |
738 | int snd_vx_suspend(struct vx_core *chip) |
739 | { |
740 | snd_power_change_state(card: chip->card, SNDRV_CTL_POWER_D3hot); |
741 | chip->chip_status |= VX_STAT_IN_SUSPEND; |
742 | |
743 | return 0; |
744 | } |
745 | |
746 | EXPORT_SYMBOL(snd_vx_suspend); |
747 | |
748 | /* |
749 | * resume |
750 | */ |
751 | int snd_vx_resume(struct vx_core *chip) |
752 | { |
753 | int i, err; |
754 | |
755 | chip->chip_status &= ~VX_STAT_CHIP_INIT; |
756 | |
757 | for (i = 0; i < 4; i++) { |
758 | if (! chip->firmware[i]) |
759 | continue; |
760 | err = chip->ops->load_dsp(chip, i, chip->firmware[i]); |
761 | if (err < 0) { |
762 | snd_printk(KERN_ERR "vx: firmware resume error at DSP %d\n" , i); |
763 | return -EIO; |
764 | } |
765 | } |
766 | |
767 | chip->chip_status |= VX_STAT_CHIP_INIT; |
768 | chip->chip_status &= ~VX_STAT_IN_SUSPEND; |
769 | |
770 | snd_power_change_state(card: chip->card, SNDRV_CTL_POWER_D0); |
771 | return 0; |
772 | } |
773 | |
774 | EXPORT_SYMBOL(snd_vx_resume); |
775 | #endif |
776 | |
777 | static void snd_vx_release(struct device *dev, void *data) |
778 | { |
779 | snd_vx_free_firmware(chip: data); |
780 | } |
781 | |
782 | /** |
783 | * snd_vx_create - constructor for struct vx_core |
784 | * @card: card instance |
785 | * @hw: hardware specific record |
786 | * @ops: VX ops pointer |
787 | * @extra_size: extra byte size to allocate appending to chip |
788 | * |
789 | * this function allocates the instance and prepare for the hardware |
790 | * initialization. |
791 | * |
792 | * The object is managed via devres, and will be automatically released. |
793 | * |
794 | * return the instance pointer if successful, NULL in error. |
795 | */ |
796 | struct vx_core *snd_vx_create(struct snd_card *card, |
797 | const struct snd_vx_hardware *hw, |
798 | const struct snd_vx_ops *ops, |
799 | int ) |
800 | { |
801 | struct vx_core *chip; |
802 | |
803 | if (snd_BUG_ON(!card || !hw || !ops)) |
804 | return NULL; |
805 | |
806 | chip = devres_alloc(snd_vx_release, sizeof(*chip) + extra_size, |
807 | GFP_KERNEL); |
808 | if (!chip) |
809 | return NULL; |
810 | mutex_init(&chip->lock); |
811 | chip->irq = -1; |
812 | chip->hw = hw; |
813 | chip->type = hw->type; |
814 | chip->ops = ops; |
815 | mutex_init(&chip->mixer_mutex); |
816 | |
817 | chip->card = card; |
818 | card->private_data = chip; |
819 | strcpy(p: card->driver, q: hw->name); |
820 | sprintf(buf: card->shortname, fmt: "Digigram %s" , hw->name); |
821 | |
822 | vx_proc_init(chip); |
823 | |
824 | return chip; |
825 | } |
826 | |
827 | EXPORT_SYMBOL(snd_vx_create); |
828 | |