3 * Support for audio capture for tm5600/6000/6010
4 * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/device.h>
16 #include <linux/interrupt.h>
17 #include <linux/usb.h>
18 #include <linux/slab.h>
19 #include <linux/vmalloc.h>
21 #include <asm/delay.h>
22 #include <sound/core.h>
23 #include <sound/pcm.h>
24 #include <sound/pcm_params.h>
25 #include <sound/control.h>
26 #include <sound/initval.h>
30 #include "tm6000-regs.h"
34 #define dprintk(level, fmt, arg...) do { \
36 printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
39 /****************************************************************************
40 Module global static vars
41 ****************************************************************************/
43 static int index
[SNDRV_CARDS
] = SNDRV_DEFAULT_IDX
; /* Index 0-MAX */
45 static int enable
[SNDRV_CARDS
] = {1, [1 ... (SNDRV_CARDS
- 1)] = 1};
47 module_param_array(enable
, bool, NULL
, 0444);
48 MODULE_PARM_DESC(enable
, "Enable tm6000x soundcard. default enabled.");
50 module_param_array(index
, int, NULL
, 0444);
51 MODULE_PARM_DESC(index
, "Index value for tm6000x capture interface(s).");
54 /****************************************************************************
56 ****************************************************************************/
58 MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
59 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
60 MODULE_LICENSE("GPL");
61 MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
64 static unsigned int debug
;
65 module_param(debug
, int, 0644);
66 MODULE_PARM_DESC(debug
, "enable debug messages");
68 /****************************************************************************
69 Module specific funtions
70 ****************************************************************************/
73 * BOARD Specific: Sets audio DMA
76 static int _tm6000_start_audio_dma(struct snd_tm6000_card
*chip
)
78 struct tm6000_core
*core
= chip
->core
;
82 val
= tm6000_get_reg(core
, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF
, 0x0);
84 tm6000_set_reg(core
, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF
, val
);
86 tm6000_set_reg(core
, TM6010_REQ08_R01_A_INIT
, 0x80);
92 * BOARD Specific: Resets audio DMA
94 static int _tm6000_stop_audio_dma(struct snd_tm6000_card
*chip
)
96 struct tm6000_core
*core
= chip
->core
;
98 dprintk(1, "Stopping audio DMA\n");
101 val
= tm6000_get_reg(core
, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF
, 0x0);
103 tm6000_set_reg(core
, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF
, val
);
105 tm6000_set_reg(core
, TM6010_REQ08_R01_A_INIT
, 0);
110 static void dsp_buffer_free(struct snd_pcm_substream
*substream
)
112 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
114 dprintk(2, "Freeing buffer\n");
116 vfree(substream
->runtime
->dma_area
);
117 substream
->runtime
->dma_area
= NULL
;
118 substream
->runtime
->dma_bytes
= 0;
121 static int dsp_buffer_alloc(struct snd_pcm_substream
*substream
, int size
)
123 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
125 dprintk(2, "Allocating buffer\n");
127 if (substream
->runtime
->dma_area
) {
128 if (substream
->runtime
->dma_bytes
> size
)
130 dsp_buffer_free(substream
);
133 substream
->runtime
->dma_area
= vmalloc(size
);
134 if (!substream
->runtime
->dma_area
)
137 substream
->runtime
->dma_bytes
= size
;
143 /****************************************************************************
145 ****************************************************************************/
148 * Digital hardware definition
150 #define DEFAULT_FIFO_SIZE 4096
152 static struct snd_pcm_hardware snd_tm6000_digital_hw
= {
153 .info
= SNDRV_PCM_INFO_MMAP
|
154 SNDRV_PCM_INFO_INTERLEAVED
|
155 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
156 SNDRV_PCM_INFO_MMAP_VALID
,
157 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
159 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
,
164 .period_bytes_min
= DEFAULT_FIFO_SIZE
/4,
165 .period_bytes_max
= DEFAULT_FIFO_SIZE
/4,
168 .buffer_bytes_max
= (1024*1024),
172 * audio pcm capture open callback
174 static int snd_tm6000_pcm_open(struct snd_pcm_substream
*substream
)
176 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
177 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
180 err
= snd_pcm_hw_constraint_pow2(runtime
, 0,
181 SNDRV_PCM_HW_PARAM_PERIODS
);
185 chip
->substream
= substream
;
187 runtime
->hw
= snd_tm6000_digital_hw
;
191 dprintk(1, "Error opening PCM!\n");
196 * audio close callback
198 static int snd_tm6000_close(struct snd_pcm_substream
*substream
)
203 static int tm6000_fillbuf(struct tm6000_core
*core
, char *buf
, int size
)
207 /* Need to add a real code to copy audio buffer */
208 printk("Audio (%i bytes): ", size
);
209 for (i
= 0; i
< size
- 3; i
+=4)
210 printk("(0x%04x, 0x%04x), ",
211 *(u16
*)(buf
+ i
), *(u16
*)(buf
+ i
+ 2));
221 static int snd_tm6000_hw_params(struct snd_pcm_substream
*substream
,
222 struct snd_pcm_hw_params
*hw_params
)
226 size
= params_period_bytes(hw_params
) * params_periods(hw_params
);
228 rc
= dsp_buffer_alloc(substream
, size
);
238 static int snd_tm6000_hw_free(struct snd_pcm_substream
*substream
)
240 dsp_buffer_free(substream
);
248 static int snd_tm6000_prepare(struct snd_pcm_substream
*substream
)
257 static int snd_tm6000_card_trigger(struct snd_pcm_substream
*substream
, int cmd
)
259 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
262 spin_lock(&chip
->reg_lock
);
265 case SNDRV_PCM_TRIGGER_START
:
266 err
= _tm6000_start_audio_dma(chip
);
268 case SNDRV_PCM_TRIGGER_STOP
:
269 err
= _tm6000_stop_audio_dma(chip
);
276 spin_unlock(&chip
->reg_lock
);
284 static snd_pcm_uframes_t
snd_tm6000_pointer(struct snd_pcm_substream
*substream
)
286 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
287 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
290 count
= atomic_read(&chip
->count
);
292 return runtime
->period_size
* (count
& (runtime
->periods
-1));
298 static struct snd_pcm_ops snd_tm6000_pcm_ops
= {
299 .open
= snd_tm6000_pcm_open
,
300 .close
= snd_tm6000_close
,
301 .ioctl
= snd_pcm_lib_ioctl
,
302 .hw_params
= snd_tm6000_hw_params
,
303 .hw_free
= snd_tm6000_hw_free
,
304 .prepare
= snd_tm6000_prepare
,
305 .trigger
= snd_tm6000_card_trigger
,
306 .pointer
= snd_tm6000_pointer
,
310 * create a PCM device
313 /* FIXME: Control interface - How to control volume/mute? */
315 /****************************************************************************
316 Basic Flow for Sound Devices
317 ****************************************************************************/
320 * Alsa Constructor - Component probe
322 int tm6000_audio_init(struct tm6000_core
*dev
)
324 struct snd_card
*card
;
325 struct snd_tm6000_card
*chip
;
334 if (devnr
>= SNDRV_CARDS
)
340 rc
= snd_card_create(index
[devnr
], "tm6000", THIS_MODULE
, 0, &card
);
342 snd_printk(KERN_ERR
"cannot create card instance %d\n", devnr
);
346 chip
= kzalloc(sizeof(struct snd_tm6000_card
), GFP_KERNEL
);
352 sprintf(component
, "USB%04x:%04x",
353 le16_to_cpu(dev
->udev
->descriptor
.idVendor
),
354 le16_to_cpu(dev
->udev
->descriptor
.idProduct
));
355 snd_component_add(card
, component
);
357 spin_lock_init(&chip
->reg_lock
);
358 rc
= snd_pcm_new(card
, "TM6000 Audio", 0, 0, 1, &pcm
);
362 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &snd_tm6000_pcm_ops
);
364 pcm
->private_data
= dev
;
365 strcpy(pcm
->name
, "Trident TM5600/60x0");
366 strcpy(card
->driver
, "tm6000-alsa");
367 strcpy(card
->shortname
, "TM5600/60x0");
368 sprintf(card
->longname
, "TM5600/60x0 Audio at bus %d device %d",
369 dev
->udev
->bus
->busnum
, dev
->udev
->devnum
);
371 snd_card_set_dev(card
, &dev
->udev
->dev
);
373 rc
= snd_card_register(card
);
388 static int tm6000_audio_fini(struct tm6000_core
*dev
)
390 struct snd_tm6000_card
*chip
= dev
->adev
;
401 snd_card_free(chip
->card
);
409 struct tm6000_ops audio_ops
= {
410 .type
= TM6000_AUDIO
,
411 .name
= "TM6000 Audio Extension",
412 .init
= tm6000_audio_init
,
413 .fini
= tm6000_audio_fini
,
414 .fillbuf
= tm6000_fillbuf
,
417 static int __init
tm6000_alsa_register(void)
419 return tm6000_register_extension(&audio_ops
);
422 static void __exit
tm6000_alsa_unregister(void)
424 tm6000_unregister_extension(&audio_ops
);
427 module_init(tm6000_alsa_register
);
428 module_exit(tm6000_alsa_unregister
);