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