]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/tm6000/tm6000-alsa.c
v4l-dvb: update gfp/slab.h includes
[karo-tx-linux.git] / drivers / staging / tm6000 / tm6000-alsa.c
1 /*
2  *
3  *  Support for audio capture for tm5600/6000/6010
4  *    (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
5  *
6  *  Based on cx88-alsa.c
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 version 2 as
10  *  published by the Free Software Foundation.
11  */
12
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
20 #include <asm/delay.h>
21 #include <sound/core.h>
22 #include <sound/pcm.h>
23 #include <sound/pcm_params.h>
24 #include <sound/control.h>
25 #include <sound/initval.h>
26
27
28 #include "tm6000.h"
29 #include "tm6000-regs.h"
30
31 #undef dprintk
32
33 #define dprintk(level, fmt, arg...) do {                                   \
34         if (debug >= level)                                                \
35                 printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
36         } while (0)
37
38 /****************************************************************************
39         Data type declarations - Can be moded to a header file later
40  ****************************************************************************/
41
42 struct snd_tm6000_card {
43         struct snd_card            *card;
44
45         spinlock_t                 reg_lock;
46
47         atomic_t                   count;
48
49         unsigned int               period_size;
50         unsigned int               num_periods;
51
52         struct tm6000_core         *core;
53         struct tm6000_buffer       *buf;
54
55         int                        bufsize;
56
57         struct snd_pcm_substream *substream;
58 };
59
60
61 /****************************************************************************
62                         Module global static vars
63  ****************************************************************************/
64
65 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
66 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
67 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
68
69 module_param_array(enable, bool, NULL, 0444);
70 MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
71
72 module_param_array(index, int, NULL, 0444);
73 MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
74
75
76 /****************************************************************************
77                                 Module macros
78  ****************************************************************************/
79
80 MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
81 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
82 MODULE_LICENSE("GPL");
83 MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
84                         "{{Trident,tm6000},"
85                         "{{Trident,tm6010}");
86 static unsigned int debug;
87 module_param(debug, int, 0644);
88 MODULE_PARM_DESC(debug, "enable debug messages");
89
90 /****************************************************************************
91                         Module specific funtions
92  ****************************************************************************/
93
94 /*
95  * BOARD Specific: Sets audio DMA
96  */
97
98 static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
99 {
100         struct tm6000_core *core = chip->core;
101         int val;
102
103         /* Enables audio */
104         val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
105         val |= 0x20;
106         tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
107
108         tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80);
109
110         return 0;
111 }
112
113 /*
114  * BOARD Specific: Resets audio DMA
115  */
116 static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
117 {
118         struct tm6000_core *core = chip->core;
119         int val;
120         dprintk(1, "Stopping audio DMA\n");
121
122         /* Enables audio */
123         val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
124         val &= ~0x20;
125         tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
126
127         tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0);
128
129         return 0;
130 }
131
132 static int dsp_buffer_free(struct snd_tm6000_card *chip)
133 {
134         BUG_ON(!chip->bufsize);
135
136         dprintk(2, "Freeing buffer\n");
137
138         /* FIXME: Frees buffer */
139
140         chip->bufsize = 0;
141
142        return 0;
143 }
144
145 /****************************************************************************
146                                 ALSA PCM Interface
147  ****************************************************************************/
148
149 /*
150  * Digital hardware definition
151  */
152 #define DEFAULT_FIFO_SIZE       4096
153
154 static struct snd_pcm_hardware snd_tm6000_digital_hw = {
155         .info = SNDRV_PCM_INFO_MMAP |
156                 SNDRV_PCM_INFO_INTERLEAVED |
157                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
158                 SNDRV_PCM_INFO_MMAP_VALID,
159         .formats = SNDRV_PCM_FMTBIT_S16_LE,
160
161         .rates =                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
162         .rate_min =             44100,
163         .rate_max =             48000,
164         .channels_min = 2,
165         .channels_max = 2,
166         .period_bytes_min = DEFAULT_FIFO_SIZE/4,
167         .period_bytes_max = DEFAULT_FIFO_SIZE/4,
168         .periods_min = 1,
169         .periods_max = 1024,
170         .buffer_bytes_max = (1024*1024),
171 };
172
173 /*
174  * audio pcm capture open callback
175  */
176 static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
177 {
178         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
179         struct snd_pcm_runtime *runtime = substream->runtime;
180         int err;
181
182         err = snd_pcm_hw_constraint_pow2(runtime, 0,
183                                          SNDRV_PCM_HW_PARAM_PERIODS);
184         if (err < 0)
185                 goto _error;
186
187         chip->substream = substream;
188
189         runtime->hw = snd_tm6000_digital_hw;
190
191         return 0;
192 _error:
193         dprintk(1, "Error opening PCM!\n");
194         return err;
195 }
196
197 /*
198  * audio close callback
199  */
200 static int snd_tm6000_close(struct snd_pcm_substream *substream)
201 {
202         return 0;
203 }
204
205 /*
206  * hw_params callback
207  */
208 static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
209                               struct snd_pcm_hw_params *hw_params)
210 {
211         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
212
213         if (substream->runtime->dma_area) {
214                 dsp_buffer_free(chip);
215                 substream->runtime->dma_area = NULL;
216         }
217
218         chip->period_size = params_period_bytes(hw_params);
219         chip->num_periods = params_periods(hw_params);
220         chip->bufsize = chip->period_size * params_periods(hw_params);
221
222         BUG_ON(!chip->bufsize);
223
224         dprintk(1, "Setting buffer\n");
225
226         /* FIXME: Allocate buffer for audio */
227
228
229         return 0;
230 }
231
232 /*
233  * hw free callback
234  */
235 static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
236 {
237
238         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
239
240         if (substream->runtime->dma_area) {
241                 dsp_buffer_free(chip);
242                 substream->runtime->dma_area = NULL;
243         }
244
245         return 0;
246 }
247
248 /*
249  * prepare callback
250  */
251 static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
252 {
253         return 0;
254 }
255
256
257 /*
258  * trigger callback
259  */
260 static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
261 {
262         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
263         int err;
264
265         spin_lock(&chip->reg_lock);
266
267         switch (cmd) {
268         case SNDRV_PCM_TRIGGER_START:
269                 err = _tm6000_start_audio_dma(chip);
270                 break;
271         case SNDRV_PCM_TRIGGER_STOP:
272                 err = _tm6000_stop_audio_dma(chip);
273                 break;
274         default:
275                 err = -EINVAL;
276                 break;
277         }
278
279         spin_unlock(&chip->reg_lock);
280
281         return err;
282 }
283
284 /*
285  * pointer callback
286  */
287 static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
288 {
289         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
290         struct snd_pcm_runtime *runtime = substream->runtime;
291         u16 count;
292
293         count = atomic_read(&chip->count);
294
295         return runtime->period_size * (count & (runtime->periods-1));
296 }
297
298 /*
299  * operators
300  */
301 static struct snd_pcm_ops snd_tm6000_pcm_ops = {
302         .open = snd_tm6000_pcm_open,
303         .close = snd_tm6000_close,
304         .ioctl = snd_pcm_lib_ioctl,
305         .hw_params = snd_tm6000_hw_params,
306         .hw_free = snd_tm6000_hw_free,
307         .prepare = snd_tm6000_prepare,
308         .trigger = snd_tm6000_card_trigger,
309         .pointer = snd_tm6000_pointer,
310 };
311
312 /*
313  * create a PCM device
314  */
315 static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
316                                     int device, char *name)
317 {
318         int err;
319         struct snd_pcm *pcm;
320
321         err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
322         if (err < 0)
323                 return err;
324         pcm->private_data = chip;
325         strcpy(pcm->name, name);
326         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
327
328         return 0;
329 }
330
331 /* FIXME: Control interface - How to control volume/mute? */
332
333 /****************************************************************************
334                         Basic Flow for Sound Devices
335  ****************************************************************************/
336
337 /*
338  * Alsa Constructor - Component probe
339  */
340
341 int tm6000_audio_init(struct tm6000_core *dev, int idx)
342 {
343         struct snd_card         *card;
344         struct snd_tm6000_card  *chip;
345         int                     rc, len;
346         char                    component[14];
347
348         if (idx >= SNDRV_CARDS)
349                 return -ENODEV;
350
351         if (!enable[idx])
352                 return -ENOENT;
353
354         rc = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
355         if (rc < 0) {
356                 snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
357                 return rc;
358         }
359
360         chip = kzalloc(sizeof(*chip), GFP_KERNEL);
361         if (!chip) {
362                 rc = -ENOMEM;
363                 goto error;
364         }
365
366         chip->core = dev;
367         chip->card = card;
368
369         strcpy(card->driver, "tm6000-alsa");
370         sprintf(component, "USB%04x:%04x",
371                 le16_to_cpu(dev->udev->descriptor.idVendor),
372                 le16_to_cpu(dev->udev->descriptor.idProduct));
373         snd_component_add(card, component);
374
375         if (dev->udev->descriptor.iManufacturer)
376                 len = usb_string(dev->udev,
377                                  dev->udev->descriptor.iManufacturer,
378                                  card->longname, sizeof(card->longname));
379         else
380                 len = 0;
381
382         if (len > 0)
383                 strlcat(card->longname, " ", sizeof(card->longname));
384
385         strlcat(card->longname, card->shortname, sizeof(card->longname));
386
387         len = strlcat(card->longname, " at ", sizeof(card->longname));
388
389         if (len < sizeof(card->longname))
390                 usb_make_path(dev->udev, card->longname + len,
391                               sizeof(card->longname) - len);
392
393         strlcat(card->longname,
394                 dev->udev->speed == USB_SPEED_LOW ? ", low speed" :
395                 dev->udev->speed == USB_SPEED_FULL ? ", full speed" :
396                                                            ", high speed",
397                 sizeof(card->longname));
398
399         rc = snd_tm6000_pcm(chip, 0, "tm6000 Digital");
400         if (rc < 0)
401                 goto error;
402
403         rc = snd_card_register(card);
404         if (rc < 0)
405                 goto error;
406
407
408         return 0;
409
410 error:
411         snd_card_free(card);
412         return rc;
413 }
414
415 static int tm6000_audio_fini(struct tm6000_core *dev)
416 {
417         return 0;
418 }
419
420 struct tm6000_ops audio_ops = {
421         .id     = TM6000_AUDIO,
422         .name   = "TM6000 Audio Extension",
423         .init   = tm6000_audio_init,
424         .fini   = tm6000_audio_fini,
425 };
426
427 static int __init tm6000_alsa_register(void)
428 {
429         return tm6000_register_extension(&audio_ops);
430 }
431
432 static void __exit tm6000_alsa_unregister(void)
433 {
434         tm6000_unregister_extension(&audio_ops);
435 }
436
437 module_init(tm6000_alsa_register);
438 module_exit(tm6000_alsa_unregister);