diff options
Diffstat (limited to 'sound/pci/lx6464es/lx6464es.c')
-rw-r--r-- | sound/pci/lx6464es/lx6464es.c | 1159 |
1 files changed, 1159 insertions, 0 deletions
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c new file mode 100644 index 000000000000..ccf1b38c88ea --- /dev/null +++ b/sound/pci/lx6464es/lx6464es.c | |||
@@ -0,0 +1,1159 @@ | |||
1 | /* -*- linux-c -*- * | ||
2 | * | ||
3 | * ALSA driver for the digigram lx6464es interface | ||
4 | * | ||
5 | * Copyright (c) 2008, 2009 Tim Blechmann <tim@klingt.org> | ||
6 | * | ||
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; see the file COPYING. If not, write to | ||
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
21 | * Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #include <sound/initval.h> | ||
31 | #include <sound/control.h> | ||
32 | #include <sound/info.h> | ||
33 | |||
34 | #include "lx6464es.h" | ||
35 | |||
36 | MODULE_AUTHOR("Tim Blechmann"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | MODULE_DESCRIPTION("digigram lx6464es"); | ||
39 | MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}"); | ||
40 | |||
41 | |||
42 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
43 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
44 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
45 | |||
46 | module_param_array(index, int, NULL, 0444); | ||
47 | MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface."); | ||
48 | module_param_array(id, charp, NULL, 0444); | ||
49 | MODULE_PARM_DESC(id, "ID string for Digigram LX6464ES interface."); | ||
50 | module_param_array(enable, bool, NULL, 0444); | ||
51 | MODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards."); | ||
52 | |||
53 | static const char card_name[] = "LX6464ES"; | ||
54 | |||
55 | |||
56 | #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 | ||
57 | |||
58 | static struct pci_device_id snd_lx6464es_ids[] = { | ||
59 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), | ||
60 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, | ||
61 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM | ||
62 | }, /* LX6464ES */ | ||
63 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), | ||
64 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, | ||
65 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM | ||
66 | }, /* LX6464ES-CAE */ | ||
67 | { 0, }, | ||
68 | }; | ||
69 | |||
70 | MODULE_DEVICE_TABLE(pci, snd_lx6464es_ids); | ||
71 | |||
72 | |||
73 | |||
74 | /* PGO pour USERo dans le registre pci_0x06/loc_0xEC */ | ||
75 | #define CHIPSC_RESET_XILINX (1L<<16) | ||
76 | |||
77 | |||
78 | /* alsa callbacks */ | ||
79 | static struct snd_pcm_hardware lx_caps = { | ||
80 | .info = (SNDRV_PCM_INFO_MMAP | | ||
81 | SNDRV_PCM_INFO_INTERLEAVED | | ||
82 | SNDRV_PCM_INFO_MMAP_VALID | | ||
83 | SNDRV_PCM_INFO_SYNC_START), | ||
84 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | ||
85 | SNDRV_PCM_FMTBIT_S16_BE | | ||
86 | SNDRV_PCM_FMTBIT_S24_3LE | | ||
87 | SNDRV_PCM_FMTBIT_S24_3BE), | ||
88 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
89 | SNDRV_PCM_RATE_8000_192000), | ||
90 | .rate_min = 8000, | ||
91 | .rate_max = 192000, | ||
92 | .channels_min = 2, | ||
93 | .channels_max = 64, | ||
94 | .buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER, | ||
95 | .period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2), | ||
96 | .period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER), | ||
97 | .periods_min = 2, | ||
98 | .periods_max = MAX_STREAM_BUFFER, | ||
99 | }; | ||
100 | |||
101 | static int lx_set_granularity(struct lx6464es *chip, u32 gran); | ||
102 | |||
103 | |||
104 | static int lx_hardware_open(struct lx6464es *chip, | ||
105 | struct snd_pcm_substream *substream) | ||
106 | { | ||
107 | int err = 0; | ||
108 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
109 | int channels = runtime->channels; | ||
110 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
111 | |||
112 | snd_pcm_uframes_t period_size = runtime->period_size; | ||
113 | |||
114 | snd_printd(LXP "allocating pipe for %d channels\n", channels); | ||
115 | err = lx_pipe_allocate(chip, 0, is_capture, channels); | ||
116 | if (err < 0) { | ||
117 | snd_printk(KERN_ERR LXP "allocating pipe failed\n"); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | err = lx_set_granularity(chip, period_size); | ||
122 | if (err < 0) { | ||
123 | snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n", | ||
124 | period_size); | ||
125 | return err; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int lx_hardware_start(struct lx6464es *chip, | ||
132 | struct snd_pcm_substream *substream) | ||
133 | { | ||
134 | int err = 0; | ||
135 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
136 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
137 | |||
138 | snd_printd(LXP "setting stream format\n"); | ||
139 | err = lx_stream_set_format(chip, runtime, 0, is_capture); | ||
140 | if (err < 0) { | ||
141 | snd_printk(KERN_ERR LXP "setting stream format failed\n"); | ||
142 | return err; | ||
143 | } | ||
144 | |||
145 | snd_printd(LXP "starting pipe\n"); | ||
146 | err = lx_pipe_start(chip, 0, is_capture); | ||
147 | if (err < 0) { | ||
148 | snd_printk(KERN_ERR LXP "starting pipe failed\n"); | ||
149 | return err; | ||
150 | } | ||
151 | |||
152 | snd_printd(LXP "waiting for pipe to start\n"); | ||
153 | err = lx_pipe_wait_for_start(chip, 0, is_capture); | ||
154 | if (err < 0) { | ||
155 | snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); | ||
156 | return err; | ||
157 | } | ||
158 | |||
159 | return err; | ||
160 | } | ||
161 | |||
162 | |||
163 | static int lx_hardware_stop(struct lx6464es *chip, | ||
164 | struct snd_pcm_substream *substream) | ||
165 | { | ||
166 | int err = 0; | ||
167 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
168 | |||
169 | snd_printd(LXP "pausing pipe\n"); | ||
170 | err = lx_pipe_pause(chip, 0, is_capture); | ||
171 | if (err < 0) { | ||
172 | snd_printk(KERN_ERR LXP "pausing pipe failed\n"); | ||
173 | return err; | ||
174 | } | ||
175 | |||
176 | snd_printd(LXP "waiting for pipe to become idle\n"); | ||
177 | err = lx_pipe_wait_for_idle(chip, 0, is_capture); | ||
178 | if (err < 0) { | ||
179 | snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); | ||
180 | return err; | ||
181 | } | ||
182 | |||
183 | snd_printd(LXP "stopping pipe\n"); | ||
184 | err = lx_pipe_stop(chip, 0, is_capture); | ||
185 | if (err < 0) { | ||
186 | snd_printk(LXP "stopping pipe failed\n"); | ||
187 | return err; | ||
188 | } | ||
189 | |||
190 | return err; | ||
191 | } | ||
192 | |||
193 | |||
194 | static int lx_hardware_close(struct lx6464es *chip, | ||
195 | struct snd_pcm_substream *substream) | ||
196 | { | ||
197 | int err = 0; | ||
198 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
199 | |||
200 | snd_printd(LXP "releasing pipe\n"); | ||
201 | err = lx_pipe_release(chip, 0, is_capture); | ||
202 | if (err < 0) { | ||
203 | snd_printk(LXP "releasing pipe failed\n"); | ||
204 | return err; | ||
205 | } | ||
206 | |||
207 | return err; | ||
208 | } | ||
209 | |||
210 | |||
211 | static int lx_pcm_open(struct snd_pcm_substream *substream) | ||
212 | { | ||
213 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
214 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
215 | int err = 0; | ||
216 | int board_rate; | ||
217 | |||
218 | snd_printdd("->lx_pcm_open\n"); | ||
219 | mutex_lock(&chip->setup_mutex); | ||
220 | |||
221 | /* copy the struct snd_pcm_hardware struct */ | ||
222 | runtime->hw = lx_caps; | ||
223 | |||
224 | #if 0 | ||
225 | /* buffer-size should better be multiple of period-size */ | ||
226 | err = snd_pcm_hw_constraint_integer(runtime, | ||
227 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
228 | if (err < 0) { | ||
229 | snd_printk(KERN_WARNING LXP "could not constrain periods\n"); | ||
230 | goto exit; | ||
231 | } | ||
232 | #endif | ||
233 | |||
234 | /* the clock rate cannot be changed */ | ||
235 | board_rate = chip->board_sample_rate; | ||
236 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, | ||
237 | board_rate, board_rate); | ||
238 | |||
239 | if (err < 0) { | ||
240 | snd_printk(KERN_WARNING LXP "could not constrain periods\n"); | ||
241 | goto exit; | ||
242 | } | ||
243 | |||
244 | /* constrain period size */ | ||
245 | err = snd_pcm_hw_constraint_minmax(runtime, | ||
246 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
247 | MICROBLAZE_IBL_MIN, | ||
248 | MICROBLAZE_IBL_MAX); | ||
249 | if (err < 0) { | ||
250 | snd_printk(KERN_WARNING LXP | ||
251 | "could not constrain period size\n"); | ||
252 | goto exit; | ||
253 | } | ||
254 | |||
255 | snd_pcm_hw_constraint_step(runtime, 0, | ||
256 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); | ||
257 | |||
258 | snd_pcm_set_sync(substream); | ||
259 | err = 0; | ||
260 | |||
261 | exit: | ||
262 | runtime->private_data = chip; | ||
263 | |||
264 | mutex_unlock(&chip->setup_mutex); | ||
265 | snd_printdd("<-lx_pcm_open, %d\n", err); | ||
266 | return err; | ||
267 | } | ||
268 | |||
269 | static int lx_pcm_close(struct snd_pcm_substream *substream) | ||
270 | { | ||
271 | int err = 0; | ||
272 | snd_printdd("->lx_pcm_close\n"); | ||
273 | return err; | ||
274 | } | ||
275 | |||
276 | static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream | ||
277 | *substream) | ||
278 | { | ||
279 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
280 | snd_pcm_uframes_t pos; | ||
281 | unsigned long flags; | ||
282 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
283 | |||
284 | struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : | ||
285 | &chip->playback_stream; | ||
286 | |||
287 | snd_printdd("->lx_pcm_stream_pointer\n"); | ||
288 | |||
289 | spin_lock_irqsave(&chip->lock, flags); | ||
290 | pos = lx_stream->frame_pos * substream->runtime->period_size; | ||
291 | spin_unlock_irqrestore(&chip->lock, flags); | ||
292 | |||
293 | snd_printdd(LXP "stream_pointer at %ld\n", pos); | ||
294 | return pos; | ||
295 | } | ||
296 | |||
297 | static int lx_pcm_prepare(struct snd_pcm_substream *substream) | ||
298 | { | ||
299 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
300 | int err = 0; | ||
301 | const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
302 | |||
303 | snd_printdd("->lx_pcm_prepare\n"); | ||
304 | |||
305 | mutex_lock(&chip->setup_mutex); | ||
306 | |||
307 | if (chip->hardware_running[is_capture]) { | ||
308 | err = lx_hardware_stop(chip, substream); | ||
309 | if (err < 0) { | ||
310 | snd_printk(KERN_ERR LXP "failed to stop hardware. " | ||
311 | "Error code %d\n", err); | ||
312 | goto exit; | ||
313 | } | ||
314 | |||
315 | err = lx_hardware_close(chip, substream); | ||
316 | if (err < 0) { | ||
317 | snd_printk(KERN_ERR LXP "failed to close hardware. " | ||
318 | "Error code %d\n", err); | ||
319 | goto exit; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | snd_printd(LXP "opening hardware\n"); | ||
324 | err = lx_hardware_open(chip, substream); | ||
325 | if (err < 0) { | ||
326 | snd_printk(KERN_ERR LXP "failed to open hardware. " | ||
327 | "Error code %d\n", err); | ||
328 | goto exit; | ||
329 | } | ||
330 | |||
331 | err = lx_hardware_start(chip, substream); | ||
332 | if (err < 0) { | ||
333 | snd_printk(KERN_ERR LXP "failed to start hardware. " | ||
334 | "Error code %d\n", err); | ||
335 | goto exit; | ||
336 | } | ||
337 | |||
338 | chip->hardware_running[is_capture] = 1; | ||
339 | |||
340 | if (chip->board_sample_rate != substream->runtime->rate) { | ||
341 | if (!err) | ||
342 | chip->board_sample_rate = substream->runtime->rate; | ||
343 | } | ||
344 | |||
345 | exit: | ||
346 | mutex_unlock(&chip->setup_mutex); | ||
347 | return err; | ||
348 | } | ||
349 | |||
350 | static int lx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
351 | struct snd_pcm_hw_params *hw_params, int is_capture) | ||
352 | { | ||
353 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
354 | int err = 0; | ||
355 | |||
356 | snd_printdd("->lx_pcm_hw_params\n"); | ||
357 | |||
358 | mutex_lock(&chip->setup_mutex); | ||
359 | |||
360 | /* set dma buffer */ | ||
361 | err = snd_pcm_lib_malloc_pages(substream, | ||
362 | params_buffer_bytes(hw_params)); | ||
363 | |||
364 | if (is_capture) | ||
365 | chip->capture_stream.stream = substream; | ||
366 | else | ||
367 | chip->playback_stream.stream = substream; | ||
368 | |||
369 | mutex_unlock(&chip->setup_mutex); | ||
370 | return err; | ||
371 | } | ||
372 | |||
373 | static int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream, | ||
374 | struct snd_pcm_hw_params *hw_params) | ||
375 | { | ||
376 | return lx_pcm_hw_params(substream, hw_params, 0); | ||
377 | } | ||
378 | |||
379 | static int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream, | ||
380 | struct snd_pcm_hw_params *hw_params) | ||
381 | { | ||
382 | return lx_pcm_hw_params(substream, hw_params, 1); | ||
383 | } | ||
384 | |||
385 | static int lx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
386 | { | ||
387 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
388 | int err = 0; | ||
389 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
390 | |||
391 | snd_printdd("->lx_pcm_hw_free\n"); | ||
392 | mutex_lock(&chip->setup_mutex); | ||
393 | |||
394 | if (chip->hardware_running[is_capture]) { | ||
395 | err = lx_hardware_stop(chip, substream); | ||
396 | if (err < 0) { | ||
397 | snd_printk(KERN_ERR LXP "failed to stop hardware. " | ||
398 | "Error code %d\n", err); | ||
399 | goto exit; | ||
400 | } | ||
401 | |||
402 | err = lx_hardware_close(chip, substream); | ||
403 | if (err < 0) { | ||
404 | snd_printk(KERN_ERR LXP "failed to close hardware. " | ||
405 | "Error code %d\n", err); | ||
406 | goto exit; | ||
407 | } | ||
408 | |||
409 | chip->hardware_running[is_capture] = 0; | ||
410 | } | ||
411 | |||
412 | err = snd_pcm_lib_free_pages(substream); | ||
413 | |||
414 | if (is_capture) | ||
415 | chip->capture_stream.stream = 0; | ||
416 | else | ||
417 | chip->playback_stream.stream = 0; | ||
418 | |||
419 | exit: | ||
420 | mutex_unlock(&chip->setup_mutex); | ||
421 | return err; | ||
422 | } | ||
423 | |||
424 | static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) | ||
425 | { | ||
426 | struct snd_pcm_substream *substream = lx_stream->stream; | ||
427 | const int is_capture = lx_stream->is_capture; | ||
428 | |||
429 | int err; | ||
430 | |||
431 | const u32 channels = substream->runtime->channels; | ||
432 | const u32 bytes_per_frame = channels * 3; | ||
433 | const u32 period_size = substream->runtime->period_size; | ||
434 | const u32 periods = substream->runtime->periods; | ||
435 | const u32 period_bytes = period_size * bytes_per_frame; | ||
436 | |||
437 | dma_addr_t buf = substream->dma_buffer.addr; | ||
438 | int i; | ||
439 | |||
440 | u32 needed, freed; | ||
441 | u32 size_array[5]; | ||
442 | |||
443 | for (i = 0; i != periods; ++i) { | ||
444 | u32 buffer_index = 0; | ||
445 | |||
446 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, | ||
447 | size_array); | ||
448 | snd_printdd(LXP "starting: needed %d, freed %d\n", | ||
449 | needed, freed); | ||
450 | |||
451 | err = lx_buffer_give(chip, 0, is_capture, period_bytes, | ||
452 | lower_32_bits(buf), upper_32_bits(buf), | ||
453 | &buffer_index); | ||
454 | |||
455 | snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n", | ||
456 | buffer_index, (void *)buf, period_bytes); | ||
457 | buf += period_bytes; | ||
458 | } | ||
459 | |||
460 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); | ||
461 | snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed); | ||
462 | |||
463 | snd_printd(LXP "starting: starting stream\n"); | ||
464 | err = lx_stream_start(chip, 0, is_capture); | ||
465 | if (err < 0) | ||
466 | snd_printk(KERN_ERR LXP "couldn't start stream\n"); | ||
467 | else | ||
468 | lx_stream->status = LX_STREAM_STATUS_RUNNING; | ||
469 | |||
470 | lx_stream->frame_pos = 0; | ||
471 | } | ||
472 | |||
473 | static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) | ||
474 | { | ||
475 | const int is_capture = lx_stream->is_capture; | ||
476 | int err; | ||
477 | |||
478 | snd_printd(LXP "stopping: stopping stream\n"); | ||
479 | err = lx_stream_stop(chip, 0, is_capture); | ||
480 | if (err < 0) | ||
481 | snd_printk(KERN_ERR LXP "couldn't stop stream\n"); | ||
482 | else | ||
483 | lx_stream->status = LX_STREAM_STATUS_FREE; | ||
484 | |||
485 | } | ||
486 | |||
487 | static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip, | ||
488 | struct lx_stream *lx_stream) | ||
489 | { | ||
490 | switch (lx_stream->status) { | ||
491 | case LX_STREAM_STATUS_SCHEDULE_RUN: | ||
492 | lx_trigger_start(chip, lx_stream); | ||
493 | break; | ||
494 | |||
495 | case LX_STREAM_STATUS_SCHEDULE_STOP: | ||
496 | lx_trigger_stop(chip, lx_stream); | ||
497 | break; | ||
498 | |||
499 | default: | ||
500 | break; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | static void lx_trigger_tasklet(unsigned long data) | ||
505 | { | ||
506 | struct lx6464es *chip = (struct lx6464es *)data; | ||
507 | unsigned long flags; | ||
508 | |||
509 | snd_printdd("->lx_trigger_tasklet\n"); | ||
510 | |||
511 | spin_lock_irqsave(&chip->lock, flags); | ||
512 | lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream); | ||
513 | lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream); | ||
514 | spin_unlock_irqrestore(&chip->lock, flags); | ||
515 | } | ||
516 | |||
517 | static int lx_pcm_trigger_dispatch(struct lx6464es *chip, | ||
518 | struct lx_stream *lx_stream, int cmd) | ||
519 | { | ||
520 | int err = 0; | ||
521 | |||
522 | switch (cmd) { | ||
523 | case SNDRV_PCM_TRIGGER_START: | ||
524 | lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; | ||
525 | break; | ||
526 | |||
527 | case SNDRV_PCM_TRIGGER_STOP: | ||
528 | lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP; | ||
529 | break; | ||
530 | |||
531 | default: | ||
532 | err = -EINVAL; | ||
533 | goto exit; | ||
534 | } | ||
535 | tasklet_schedule(&chip->trigger_tasklet); | ||
536 | |||
537 | exit: | ||
538 | return err; | ||
539 | } | ||
540 | |||
541 | |||
542 | static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
543 | { | ||
544 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
545 | const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
546 | struct lx_stream *stream = is_capture ? &chip->capture_stream : | ||
547 | &chip->playback_stream; | ||
548 | |||
549 | snd_printdd("->lx_pcm_trigger\n"); | ||
550 | |||
551 | return lx_pcm_trigger_dispatch(chip, stream, cmd); | ||
552 | } | ||
553 | |||
554 | static int snd_lx6464es_free(struct lx6464es *chip) | ||
555 | { | ||
556 | snd_printdd("->snd_lx6464es_free\n"); | ||
557 | |||
558 | lx_irq_disable(chip); | ||
559 | |||
560 | if (chip->irq >= 0) | ||
561 | free_irq(chip->irq, chip); | ||
562 | |||
563 | iounmap(chip->port_dsp_bar); | ||
564 | ioport_unmap(chip->port_plx_remapped); | ||
565 | |||
566 | pci_release_regions(chip->pci); | ||
567 | pci_disable_device(chip->pci); | ||
568 | |||
569 | kfree(chip); | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static int snd_lx6464es_dev_free(struct snd_device *device) | ||
575 | { | ||
576 | return snd_lx6464es_free(device->device_data); | ||
577 | } | ||
578 | |||
579 | /* reset the dsp during initialization */ | ||
580 | static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) | ||
581 | { | ||
582 | int i; | ||
583 | u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); | ||
584 | |||
585 | snd_printdd("->lx_init_xilinx_reset\n"); | ||
586 | |||
587 | /* activate reset of xilinx */ | ||
588 | plx_reg &= ~CHIPSC_RESET_XILINX; | ||
589 | |||
590 | lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); | ||
591 | msleep(1); | ||
592 | |||
593 | lx_plx_reg_write(chip, ePLX_MBOX3, 0); | ||
594 | msleep(1); | ||
595 | |||
596 | plx_reg |= CHIPSC_RESET_XILINX; | ||
597 | lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); | ||
598 | |||
599 | /* deactivate reset of xilinx */ | ||
600 | for (i = 0; i != 100; ++i) { | ||
601 | u32 reg_mbox3; | ||
602 | msleep(10); | ||
603 | reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3); | ||
604 | if (reg_mbox3) { | ||
605 | snd_printd(LXP "xilinx reset done\n"); | ||
606 | snd_printdd(LXP "xilinx took %d loops\n", i); | ||
607 | break; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | /* todo: add some error handling? */ | ||
612 | |||
613 | /* clear mr */ | ||
614 | lx_dsp_reg_write(chip, eReg_CSM, 0); | ||
615 | |||
616 | /* le xilinx ES peut ne pas etre encore pret, on attend. */ | ||
617 | msleep(600); | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int __devinit lx_init_xilinx_test(struct lx6464es *chip) | ||
623 | { | ||
624 | u32 reg; | ||
625 | |||
626 | snd_printdd("->lx_init_xilinx_test\n"); | ||
627 | |||
628 | /* TEST if we have access to Xilinx/MicroBlaze */ | ||
629 | lx_dsp_reg_write(chip, eReg_CSM, 0); | ||
630 | |||
631 | reg = lx_dsp_reg_read(chip, eReg_CSM); | ||
632 | |||
633 | if (reg) { | ||
634 | snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg); | ||
635 | |||
636 | /* PCI9056_SPACE0_REMAP */ | ||
637 | lx_plx_reg_write(chip, ePLX_PCICR, 1); | ||
638 | |||
639 | reg = lx_dsp_reg_read(chip, eReg_CSM); | ||
640 | if (reg) { | ||
641 | snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg); | ||
642 | return -EAGAIN; /* seems to be appropriate */ | ||
643 | } | ||
644 | } | ||
645 | |||
646 | snd_printd(LXP "Xilinx/MicroBlaze access test successful\n"); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | /* initialize ethersound */ | ||
652 | static int __devinit lx_init_ethersound_config(struct lx6464es *chip) | ||
653 | { | ||
654 | int i; | ||
655 | u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); | ||
656 | |||
657 | u32 default_conf_es = (64 << IOCR_OUTPUTS_OFFSET) | | ||
658 | (64 << IOCR_INPUTS_OFFSET) | | ||
659 | (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET); | ||
660 | |||
661 | u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) | ||
662 | | (default_conf_es & CONFES_WRITE_PART_MASK); | ||
663 | |||
664 | snd_printdd("->lx_init_ethersound\n"); | ||
665 | |||
666 | chip->freq_ratio = FREQ_RATIO_SINGLE_MODE; | ||
667 | |||
668 | /* | ||
669 | * write it to the card ! | ||
670 | * this actually kicks the ES xilinx, the first time since poweron. | ||
671 | * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers | ||
672 | * is not ready before this is done, and the bit 2 in Reg_CSES is set. | ||
673 | * */ | ||
674 | lx_dsp_reg_write(chip, eReg_CONFES, conf_es); | ||
675 | |||
676 | for (i = 0; i != 1000; ++i) { | ||
677 | if (lx_dsp_reg_read(chip, eReg_CSES) & 4) { | ||
678 | snd_printd(LXP "ethersound initialized after %dms\n", | ||
679 | i); | ||
680 | goto ethersound_initialized; | ||
681 | } | ||
682 | msleep(1); | ||
683 | } | ||
684 | snd_printk(KERN_WARNING LXP | ||
685 | "ethersound could not be initialized after %dms\n", i); | ||
686 | return -ETIMEDOUT; | ||
687 | |||
688 | ethersound_initialized: | ||
689 | snd_printd(LXP "ethersound initialized\n"); | ||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static int __devinit lx_init_get_version_features(struct lx6464es *chip) | ||
694 | { | ||
695 | u32 dsp_version; | ||
696 | |||
697 | int err; | ||
698 | |||
699 | snd_printdd("->lx_init_get_version_features\n"); | ||
700 | |||
701 | err = lx_dsp_get_version(chip, &dsp_version); | ||
702 | |||
703 | if (err == 0) { | ||
704 | u32 freq; | ||
705 | |||
706 | snd_printk(LXP "DSP version: V%02d.%02d #%d\n", | ||
707 | (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff, | ||
708 | dsp_version & 0xff); | ||
709 | |||
710 | /* later: what firmware version do we expect? */ | ||
711 | |||
712 | /* retrieve Play/Rec features */ | ||
713 | /* done here because we may have to handle alternate | ||
714 | * DSP files. */ | ||
715 | /* later */ | ||
716 | |||
717 | /* init the EtherSound sample rate */ | ||
718 | err = lx_dsp_get_clock_frequency(chip, &freq); | ||
719 | if (err == 0) | ||
720 | chip->board_sample_rate = freq; | ||
721 | snd_printd(LXP "actual clock frequency %d\n", freq); | ||
722 | } else { | ||
723 | snd_printk(KERN_ERR LXP "DSP corrupted \n"); | ||
724 | err = -EAGAIN; | ||
725 | } | ||
726 | |||
727 | return err; | ||
728 | } | ||
729 | |||
730 | static int lx_set_granularity(struct lx6464es *chip, u32 gran) | ||
731 | { | ||
732 | int err = 0; | ||
733 | u32 snapped_gran = MICROBLAZE_IBL_MIN; | ||
734 | |||
735 | snd_printdd("->lx_set_granularity\n"); | ||
736 | |||
737 | /* blocksize is a power of 2 */ | ||
738 | while ((snapped_gran < gran) && | ||
739 | (snapped_gran < MICROBLAZE_IBL_MAX)) { | ||
740 | snapped_gran *= 2; | ||
741 | } | ||
742 | |||
743 | if (snapped_gran == chip->pcm_granularity) | ||
744 | return 0; | ||
745 | |||
746 | err = lx_dsp_set_granularity(chip, snapped_gran); | ||
747 | if (err < 0) { | ||
748 | snd_printk(KERN_WARNING LXP "could not set granularity\n"); | ||
749 | err = -EAGAIN; | ||
750 | } | ||
751 | |||
752 | if (snapped_gran != gran) | ||
753 | snd_printk(LXP "snapped blocksize to %d\n", snapped_gran); | ||
754 | |||
755 | snd_printd(LXP "set blocksize on board %d\n", snapped_gran); | ||
756 | chip->pcm_granularity = snapped_gran; | ||
757 | |||
758 | return err; | ||
759 | } | ||
760 | |||
761 | /* initialize and test the xilinx dsp chip */ | ||
762 | static int __devinit lx_init_dsp(struct lx6464es *chip) | ||
763 | { | ||
764 | int err; | ||
765 | u8 mac_address[6]; | ||
766 | int i; | ||
767 | |||
768 | snd_printdd("->lx_init_dsp\n"); | ||
769 | |||
770 | snd_printd(LXP "initialize board\n"); | ||
771 | err = lx_init_xilinx_reset(chip); | ||
772 | if (err) | ||
773 | return err; | ||
774 | |||
775 | snd_printd(LXP "testing board\n"); | ||
776 | err = lx_init_xilinx_test(chip); | ||
777 | if (err) | ||
778 | return err; | ||
779 | |||
780 | snd_printd(LXP "initialize ethersound configuration\n"); | ||
781 | err = lx_init_ethersound_config(chip); | ||
782 | if (err) | ||
783 | return err; | ||
784 | |||
785 | lx_irq_enable(chip); | ||
786 | |||
787 | /** \todo the mac address should be ready by not, but it isn't, | ||
788 | * so we wait for it */ | ||
789 | for (i = 0; i != 1000; ++i) { | ||
790 | err = lx_dsp_get_mac(chip, mac_address); | ||
791 | if (err) | ||
792 | return err; | ||
793 | if (mac_address[0] || mac_address[1] || mac_address[2] || | ||
794 | mac_address[3] || mac_address[4] || mac_address[5]) | ||
795 | goto mac_ready; | ||
796 | msleep(1); | ||
797 | } | ||
798 | return -ETIMEDOUT; | ||
799 | |||
800 | mac_ready: | ||
801 | snd_printd(LXP "mac address ready read after: %dms\n", i); | ||
802 | snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", | ||
803 | mac_address[0], mac_address[1], mac_address[2], | ||
804 | mac_address[3], mac_address[4], mac_address[5]); | ||
805 | |||
806 | err = lx_init_get_version_features(chip); | ||
807 | if (err) | ||
808 | return err; | ||
809 | |||
810 | lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT); | ||
811 | |||
812 | chip->playback_mute = 0; | ||
813 | |||
814 | return err; | ||
815 | } | ||
816 | |||
817 | static struct snd_pcm_ops lx_ops_playback = { | ||
818 | .open = lx_pcm_open, | ||
819 | .close = lx_pcm_close, | ||
820 | .ioctl = snd_pcm_lib_ioctl, | ||
821 | .prepare = lx_pcm_prepare, | ||
822 | .hw_params = lx_pcm_hw_params_playback, | ||
823 | .hw_free = lx_pcm_hw_free, | ||
824 | .trigger = lx_pcm_trigger, | ||
825 | .pointer = lx_pcm_stream_pointer, | ||
826 | }; | ||
827 | |||
828 | static struct snd_pcm_ops lx_ops_capture = { | ||
829 | .open = lx_pcm_open, | ||
830 | .close = lx_pcm_close, | ||
831 | .ioctl = snd_pcm_lib_ioctl, | ||
832 | .prepare = lx_pcm_prepare, | ||
833 | .hw_params = lx_pcm_hw_params_capture, | ||
834 | .hw_free = lx_pcm_hw_free, | ||
835 | .trigger = lx_pcm_trigger, | ||
836 | .pointer = lx_pcm_stream_pointer, | ||
837 | }; | ||
838 | |||
839 | static int __devinit lx_pcm_create(struct lx6464es *chip) | ||
840 | { | ||
841 | int err; | ||
842 | struct snd_pcm *pcm; | ||
843 | |||
844 | u32 size = 64 * /* channels */ | ||
845 | 3 * /* 24 bit samples */ | ||
846 | MAX_STREAM_BUFFER * /* periods */ | ||
847 | MICROBLAZE_IBL_MAX * /* frames per period */ | ||
848 | 2; /* duplex */ | ||
849 | |||
850 | size = PAGE_ALIGN(size); | ||
851 | |||
852 | /* hardcoded device name & channel count */ | ||
853 | err = snd_pcm_new(chip->card, (char *)card_name, 0, | ||
854 | 1, 1, &pcm); | ||
855 | |||
856 | pcm->private_data = chip; | ||
857 | |||
858 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback); | ||
859 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture); | ||
860 | |||
861 | pcm->info_flags = 0; | ||
862 | strcpy(pcm->name, card_name); | ||
863 | |||
864 | err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
865 | snd_dma_pci_data(chip->pci), | ||
866 | size, size); | ||
867 | if (err < 0) | ||
868 | return err; | ||
869 | |||
870 | chip->pcm = pcm; | ||
871 | chip->capture_stream.is_capture = 1; | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int lx_control_playback_info(struct snd_kcontrol *kcontrol, | ||
877 | struct snd_ctl_elem_info *uinfo) | ||
878 | { | ||
879 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
880 | uinfo->count = 1; | ||
881 | uinfo->value.integer.min = 0; | ||
882 | uinfo->value.integer.max = 1; | ||
883 | return 0; | ||
884 | } | ||
885 | |||
886 | static int lx_control_playback_get(struct snd_kcontrol *kcontrol, | ||
887 | struct snd_ctl_elem_value *ucontrol) | ||
888 | { | ||
889 | struct lx6464es *chip = snd_kcontrol_chip(kcontrol); | ||
890 | ucontrol->value.integer.value[0] = chip->playback_mute; | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int lx_control_playback_put(struct snd_kcontrol *kcontrol, | ||
895 | struct snd_ctl_elem_value *ucontrol) | ||
896 | { | ||
897 | struct lx6464es *chip = snd_kcontrol_chip(kcontrol); | ||
898 | int changed = 0; | ||
899 | int current_value = chip->playback_mute; | ||
900 | |||
901 | if (current_value != ucontrol->value.integer.value[0]) { | ||
902 | lx_level_unmute(chip, 0, !current_value); | ||
903 | chip->playback_mute = !current_value; | ||
904 | changed = 1; | ||
905 | } | ||
906 | return changed; | ||
907 | } | ||
908 | |||
909 | static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = { | ||
910 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
911 | .name = "PCM Playback Switch", | ||
912 | .index = 0, | ||
913 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
914 | .private_value = 0, | ||
915 | .info = lx_control_playback_info, | ||
916 | .get = lx_control_playback_get, | ||
917 | .put = lx_control_playback_put | ||
918 | }; | ||
919 | |||
920 | |||
921 | |||
922 | static void lx_proc_levels_read(struct snd_info_entry *entry, | ||
923 | struct snd_info_buffer *buffer) | ||
924 | { | ||
925 | u32 levels[64]; | ||
926 | int err; | ||
927 | int i, j; | ||
928 | struct lx6464es *chip = entry->private_data; | ||
929 | |||
930 | snd_iprintf(buffer, "capture levels:\n"); | ||
931 | err = lx_level_peaks(chip, 1, 64, levels); | ||
932 | if (err < 0) | ||
933 | return; | ||
934 | |||
935 | for (i = 0; i != 8; ++i) { | ||
936 | for (j = 0; j != 8; ++j) | ||
937 | snd_iprintf(buffer, "%08x ", levels[i*8+j]); | ||
938 | snd_iprintf(buffer, "\n"); | ||
939 | } | ||
940 | |||
941 | snd_iprintf(buffer, "\nplayback levels:\n"); | ||
942 | |||
943 | err = lx_level_peaks(chip, 0, 64, levels); | ||
944 | if (err < 0) | ||
945 | return; | ||
946 | |||
947 | for (i = 0; i != 8; ++i) { | ||
948 | for (j = 0; j != 8; ++j) | ||
949 | snd_iprintf(buffer, "%08x ", levels[i*8+j]); | ||
950 | snd_iprintf(buffer, "\n"); | ||
951 | } | ||
952 | |||
953 | snd_iprintf(buffer, "\n"); | ||
954 | } | ||
955 | |||
956 | static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip) | ||
957 | { | ||
958 | struct snd_info_entry *entry; | ||
959 | int err = snd_card_proc_new(card, "levels", &entry); | ||
960 | if (err < 0) | ||
961 | return err; | ||
962 | |||
963 | snd_info_set_text_ops(entry, chip, lx_proc_levels_read); | ||
964 | return 0; | ||
965 | } | ||
966 | |||
967 | |||
968 | static int __devinit snd_lx6464es_create(struct snd_card *card, | ||
969 | struct pci_dev *pci, | ||
970 | struct lx6464es **rchip) | ||
971 | { | ||
972 | struct lx6464es *chip; | ||
973 | int err; | ||
974 | |||
975 | static struct snd_device_ops ops = { | ||
976 | .dev_free = snd_lx6464es_dev_free, | ||
977 | }; | ||
978 | |||
979 | snd_printdd("->snd_lx6464es_create\n"); | ||
980 | |||
981 | *rchip = NULL; | ||
982 | |||
983 | /* enable PCI device */ | ||
984 | err = pci_enable_device(pci); | ||
985 | if (err < 0) | ||
986 | return err; | ||
987 | |||
988 | pci_set_master(pci); | ||
989 | |||
990 | /* check if we can restrict PCI DMA transfers to 32 bits */ | ||
991 | err = pci_set_dma_mask(pci, DMA_32BIT_MASK); | ||
992 | if (err < 0) { | ||
993 | snd_printk(KERN_ERR "architecture does not support " | ||
994 | "32bit PCI busmaster DMA\n"); | ||
995 | pci_disable_device(pci); | ||
996 | return -ENXIO; | ||
997 | } | ||
998 | |||
999 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
1000 | if (chip == NULL) { | ||
1001 | err = -ENOMEM; | ||
1002 | goto alloc_failed; | ||
1003 | } | ||
1004 | |||
1005 | chip->card = card; | ||
1006 | chip->pci = pci; | ||
1007 | chip->irq = -1; | ||
1008 | |||
1009 | /* initialize synchronization structs */ | ||
1010 | spin_lock_init(&chip->lock); | ||
1011 | spin_lock_init(&chip->msg_lock); | ||
1012 | mutex_init(&chip->setup_mutex); | ||
1013 | tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet, | ||
1014 | (unsigned long)chip); | ||
1015 | tasklet_init(&chip->tasklet_capture, lx_tasklet_capture, | ||
1016 | (unsigned long)chip); | ||
1017 | tasklet_init(&chip->tasklet_playback, lx_tasklet_playback, | ||
1018 | (unsigned long)chip); | ||
1019 | |||
1020 | /* request resources */ | ||
1021 | err = pci_request_regions(pci, card_name); | ||
1022 | if (err < 0) | ||
1023 | goto request_regions_failed; | ||
1024 | |||
1025 | /* plx port */ | ||
1026 | chip->port_plx = pci_resource_start(pci, 1); | ||
1027 | chip->port_plx_remapped = ioport_map(chip->port_plx, | ||
1028 | pci_resource_len(pci, 1)); | ||
1029 | |||
1030 | /* dsp port */ | ||
1031 | chip->port_dsp_bar = pci_ioremap_bar(pci, 2); | ||
1032 | |||
1033 | err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, | ||
1034 | card_name, chip); | ||
1035 | if (err) { | ||
1036 | snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); | ||
1037 | goto request_irq_failed; | ||
1038 | } | ||
1039 | chip->irq = pci->irq; | ||
1040 | |||
1041 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); | ||
1042 | if (err < 0) | ||
1043 | goto device_new_failed; | ||
1044 | |||
1045 | err = lx_init_dsp(chip); | ||
1046 | if (err < 0) { | ||
1047 | snd_printk(KERN_ERR LXP "error during DSP initialization\n"); | ||
1048 | return err; | ||
1049 | } | ||
1050 | |||
1051 | err = lx_pcm_create(chip); | ||
1052 | if (err < 0) | ||
1053 | return err; | ||
1054 | |||
1055 | err = lx_proc_create(card, chip); | ||
1056 | if (err < 0) | ||
1057 | return err; | ||
1058 | |||
1059 | err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch, | ||
1060 | chip)); | ||
1061 | if (err < 0) | ||
1062 | return err; | ||
1063 | |||
1064 | snd_card_set_dev(card, &pci->dev); | ||
1065 | |||
1066 | *rchip = chip; | ||
1067 | return 0; | ||
1068 | |||
1069 | device_new_failed: | ||
1070 | free_irq(pci->irq, chip); | ||
1071 | |||
1072 | request_irq_failed: | ||
1073 | pci_release_regions(pci); | ||
1074 | |||
1075 | request_regions_failed: | ||
1076 | kfree(chip); | ||
1077 | |||
1078 | alloc_failed: | ||
1079 | pci_disable_device(pci); | ||
1080 | |||
1081 | return err; | ||
1082 | } | ||
1083 | |||
1084 | static int __devinit snd_lx6464es_probe(struct pci_dev *pci, | ||
1085 | const struct pci_device_id *pci_id) | ||
1086 | { | ||
1087 | static int dev; | ||
1088 | struct snd_card *card; | ||
1089 | struct lx6464es *chip; | ||
1090 | int err; | ||
1091 | |||
1092 | snd_printdd("->snd_lx6464es_probe\n"); | ||
1093 | |||
1094 | if (dev >= SNDRV_CARDS) | ||
1095 | return -ENODEV; | ||
1096 | if (!enable[dev]) { | ||
1097 | dev++; | ||
1098 | return -ENOENT; | ||
1099 | } | ||
1100 | |||
1101 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | ||
1102 | if (err < 0) | ||
1103 | return err; | ||
1104 | |||
1105 | err = snd_lx6464es_create(card, pci, &chip); | ||
1106 | if (err < 0) { | ||
1107 | snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n"); | ||
1108 | goto out_free; | ||
1109 | } | ||
1110 | |||
1111 | strcpy(card->driver, "lx6464es"); | ||
1112 | strcpy(card->shortname, "Digigram LX6464ES"); | ||
1113 | sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", | ||
1114 | card->shortname, chip->port_plx, | ||
1115 | chip->port_dsp_bar, chip->irq); | ||
1116 | |||
1117 | err = snd_card_register(card); | ||
1118 | if (err < 0) | ||
1119 | goto out_free; | ||
1120 | |||
1121 | snd_printdd(LXP "initialization successful\n"); | ||
1122 | pci_set_drvdata(pci, card); | ||
1123 | dev++; | ||
1124 | return 0; | ||
1125 | |||
1126 | out_free: | ||
1127 | snd_card_free(card); | ||
1128 | return err; | ||
1129 | |||
1130 | } | ||
1131 | |||
1132 | static void __devexit snd_lx6464es_remove(struct pci_dev *pci) | ||
1133 | { | ||
1134 | snd_card_free(pci_get_drvdata(pci)); | ||
1135 | pci_set_drvdata(pci, NULL); | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | static struct pci_driver driver = { | ||
1140 | .name = "Digigram LX6464ES", | ||
1141 | .id_table = snd_lx6464es_ids, | ||
1142 | .probe = snd_lx6464es_probe, | ||
1143 | .remove = __devexit_p(snd_lx6464es_remove), | ||
1144 | }; | ||
1145 | |||
1146 | |||
1147 | /* module initialization */ | ||
1148 | static int __init mod_init(void) | ||
1149 | { | ||
1150 | return pci_register_driver(&driver); | ||
1151 | } | ||
1152 | |||
1153 | static void __exit mod_exit(void) | ||
1154 | { | ||
1155 | pci_unregister_driver(&driver); | ||
1156 | } | ||
1157 | |||
1158 | module_init(mod_init); | ||
1159 | module_exit(mod_exit); | ||