Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Support for audio capture for tm5600/6000/6010
0003 // Copyright (c) 2007-2008 Mauro Carvalho Chehab <mchehab@kernel.org>
0004 //
0005 // Based on cx88-alsa.c
0006 
0007 #include <linux/module.h>
0008 #include <linux/init.h>
0009 #include <linux/device.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/usb.h>
0012 #include <linux/slab.h>
0013 
0014 #include <linux/delay.h>
0015 #include <sound/core.h>
0016 #include <sound/pcm.h>
0017 #include <sound/pcm_params.h>
0018 #include <sound/control.h>
0019 #include <sound/initval.h>
0020 
0021 
0022 #include "tm6000.h"
0023 #include "tm6000-regs.h"
0024 
0025 #undef dprintk
0026 
0027 #define dprintk(level, fmt, arg...) do {                   \
0028     if (debug >= level)                        \
0029         printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
0030     } while (0)
0031 
0032 /****************************************************************************
0033             Module global static vars
0034  ****************************************************************************/
0035 
0036 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;  /* Index 0-MAX */
0037 
0038 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
0039 
0040 module_param_array(enable, bool, NULL, 0444);
0041 MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
0042 
0043 module_param_array(index, int, NULL, 0444);
0044 MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
0045 
0046 
0047 /****************************************************************************
0048                 Module macros
0049  ****************************************************************************/
0050 
0051 MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
0052 MODULE_AUTHOR("Mauro Carvalho Chehab");
0053 MODULE_LICENSE("GPL v2");
0054 static unsigned int debug;
0055 module_param(debug, int, 0644);
0056 MODULE_PARM_DESC(debug, "enable debug messages");
0057 
0058 /****************************************************************************
0059             Module specific functions
0060  ****************************************************************************/
0061 
0062 /*
0063  * BOARD Specific: Sets audio DMA
0064  */
0065 
0066 static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
0067 {
0068     struct tm6000_core *core = chip->core;
0069 
0070     dprintk(1, "Starting audio DMA\n");
0071 
0072     /* Enables audio */
0073     tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40);
0074 
0075     tm6000_set_audio_bitrate(core, 48000);
0076 
0077     return 0;
0078 }
0079 
0080 /*
0081  * BOARD Specific: Resets audio DMA
0082  */
0083 static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
0084 {
0085     struct tm6000_core *core = chip->core;
0086 
0087     dprintk(1, "Stopping audio DMA\n");
0088 
0089     /* Disables audio */
0090     tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40);
0091 
0092     return 0;
0093 }
0094 
0095 /****************************************************************************
0096                 ALSA PCM Interface
0097  ****************************************************************************/
0098 
0099 /*
0100  * Digital hardware definition
0101  */
0102 #define DEFAULT_FIFO_SIZE   4096
0103 
0104 static const struct snd_pcm_hardware snd_tm6000_digital_hw = {
0105     .info = SNDRV_PCM_INFO_BATCH |
0106         SNDRV_PCM_INFO_MMAP |
0107         SNDRV_PCM_INFO_INTERLEAVED |
0108         SNDRV_PCM_INFO_BLOCK_TRANSFER |
0109         SNDRV_PCM_INFO_MMAP_VALID,
0110     .formats = SNDRV_PCM_FMTBIT_S16_LE,
0111 
0112     .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
0113     .rate_min = 48000,
0114     .rate_max = 48000,
0115     .channels_min = 2,
0116     .channels_max = 2,
0117     .period_bytes_min = 64,
0118     .period_bytes_max = 12544,
0119     .periods_min = 2,
0120     .periods_max = 98,
0121     .buffer_bytes_max = 62720 * 8,
0122 };
0123 
0124 /*
0125  * audio pcm capture open callback
0126  */
0127 static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
0128 {
0129     struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
0130     struct snd_pcm_runtime *runtime = substream->runtime;
0131     int err;
0132 
0133     err = snd_pcm_hw_constraint_pow2(runtime, 0,
0134                      SNDRV_PCM_HW_PARAM_PERIODS);
0135     if (err < 0)
0136         goto _error;
0137 
0138     chip->substream = substream;
0139 
0140     runtime->hw = snd_tm6000_digital_hw;
0141     snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
0142 
0143     return 0;
0144 _error:
0145     dprintk(1, "Error opening PCM!\n");
0146     return err;
0147 }
0148 
0149 /*
0150  * audio close callback
0151  */
0152 static int snd_tm6000_close(struct snd_pcm_substream *substream)
0153 {
0154     struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
0155     struct tm6000_core *core = chip->core;
0156 
0157     if (atomic_read(&core->stream_started) > 0) {
0158         atomic_set(&core->stream_started, 0);
0159         schedule_work(&core->wq_trigger);
0160     }
0161 
0162     return 0;
0163 }
0164 
0165 static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
0166 {
0167     struct snd_tm6000_card *chip = core->adev;
0168     struct snd_pcm_substream *substream = chip->substream;
0169     struct snd_pcm_runtime *runtime;
0170     int period_elapsed = 0;
0171     unsigned int stride, buf_pos;
0172     int length;
0173 
0174     if (atomic_read(&core->stream_started) == 0)
0175         return 0;
0176 
0177     if (!size || !substream) {
0178         dprintk(1, "substream was NULL\n");
0179         return -EINVAL;
0180     }
0181 
0182     runtime = substream->runtime;
0183     if (!runtime || !runtime->dma_area) {
0184         dprintk(1, "runtime was NULL\n");
0185         return -EINVAL;
0186     }
0187 
0188     buf_pos = chip->buf_pos;
0189     stride = runtime->frame_bits >> 3;
0190 
0191     if (stride == 0) {
0192         dprintk(1, "stride is zero\n");
0193         return -EINVAL;
0194     }
0195 
0196     length = size / stride;
0197     if (length == 0) {
0198         dprintk(1, "%s: length was zero\n", __func__);
0199         return -EINVAL;
0200     }
0201 
0202     dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
0203         runtime->dma_area, buf_pos,
0204         (unsigned int)runtime->buffer_size, stride);
0205 
0206     if (buf_pos + length >= runtime->buffer_size) {
0207         unsigned int cnt = runtime->buffer_size - buf_pos;
0208         memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
0209         memcpy(runtime->dma_area, buf + cnt * stride,
0210             length * stride - cnt * stride);
0211     } else
0212         memcpy(runtime->dma_area + buf_pos * stride, buf,
0213             length * stride);
0214 
0215     snd_pcm_stream_lock(substream);
0216 
0217     chip->buf_pos += length;
0218     if (chip->buf_pos >= runtime->buffer_size)
0219         chip->buf_pos -= runtime->buffer_size;
0220 
0221     chip->period_pos += length;
0222     if (chip->period_pos >= runtime->period_size) {
0223         chip->period_pos -= runtime->period_size;
0224         period_elapsed = 1;
0225     }
0226 
0227     snd_pcm_stream_unlock(substream);
0228 
0229     if (period_elapsed)
0230         snd_pcm_period_elapsed(substream);
0231 
0232     return 0;
0233 }
0234 
0235 /*
0236  * prepare callback
0237  */
0238 static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
0239 {
0240     struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
0241 
0242     chip->buf_pos = 0;
0243     chip->period_pos = 0;
0244 
0245     return 0;
0246 }
0247 
0248 
0249 /*
0250  * trigger callback
0251  */
0252 static void audio_trigger(struct work_struct *work)
0253 {
0254     struct tm6000_core *core = container_of(work, struct tm6000_core,
0255                         wq_trigger);
0256     struct snd_tm6000_card *chip = core->adev;
0257 
0258     if (atomic_read(&core->stream_started)) {
0259         dprintk(1, "starting capture");
0260         _tm6000_start_audio_dma(chip);
0261     } else {
0262         dprintk(1, "stopping capture");
0263         _tm6000_stop_audio_dma(chip);
0264     }
0265 }
0266 
0267 static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
0268 {
0269     struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
0270     struct tm6000_core *core = chip->core;
0271     int err = 0;
0272 
0273     switch (cmd) {
0274     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0275     case SNDRV_PCM_TRIGGER_RESUME:
0276     case SNDRV_PCM_TRIGGER_START:
0277         atomic_set(&core->stream_started, 1);
0278         break;
0279     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0280     case SNDRV_PCM_TRIGGER_SUSPEND:
0281     case SNDRV_PCM_TRIGGER_STOP:
0282         atomic_set(&core->stream_started, 0);
0283         break;
0284     default:
0285         err = -EINVAL;
0286         break;
0287     }
0288     schedule_work(&core->wq_trigger);
0289 
0290     return err;
0291 }
0292 /*
0293  * pointer callback
0294  */
0295 static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
0296 {
0297     struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
0298 
0299     return chip->buf_pos;
0300 }
0301 
0302 /*
0303  * operators
0304  */
0305 static const struct snd_pcm_ops snd_tm6000_pcm_ops = {
0306     .open = snd_tm6000_pcm_open,
0307     .close = snd_tm6000_close,
0308     .prepare = snd_tm6000_prepare,
0309     .trigger = snd_tm6000_card_trigger,
0310     .pointer = snd_tm6000_pointer,
0311 };
0312 
0313 /*
0314  * create a PCM device
0315  */
0316 
0317 /* FIXME: Control interface - How to control volume/mute? */
0318 
0319 /****************************************************************************
0320             Basic Flow for Sound Devices
0321  ****************************************************************************/
0322 
0323 /*
0324  * Alsa Constructor - Component probe
0325  */
0326 static int tm6000_audio_init(struct tm6000_core *dev)
0327 {
0328     struct snd_card     *card;
0329     struct snd_tm6000_card  *chip;
0330     int         rc;
0331     static int      devnr;
0332     char            component[14];
0333     struct snd_pcm      *pcm;
0334 
0335     if (!dev)
0336         return 0;
0337 
0338     if (devnr >= SNDRV_CARDS)
0339         return -ENODEV;
0340 
0341     if (!enable[devnr])
0342         return -ENOENT;
0343 
0344     rc = snd_card_new(&dev->udev->dev, index[devnr], "tm6000",
0345               THIS_MODULE, 0, &card);
0346     if (rc < 0) {
0347         snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
0348         return rc;
0349     }
0350     strscpy(card->driver, "tm6000-alsa", sizeof(card->driver));
0351     strscpy(card->shortname, "TM5600/60x0", sizeof(card->shortname));
0352     sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
0353         dev->udev->bus->busnum, dev->udev->devnum);
0354 
0355     sprintf(component, "USB%04x:%04x",
0356         le16_to_cpu(dev->udev->descriptor.idVendor),
0357         le16_to_cpu(dev->udev->descriptor.idProduct));
0358     snd_component_add(card, component);
0359 
0360     chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
0361     if (!chip) {
0362         rc = -ENOMEM;
0363         goto error;
0364     }
0365 
0366     chip->core = dev;
0367     chip->card = card;
0368     dev->adev = chip;
0369     spin_lock_init(&chip->reg_lock);
0370 
0371     rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
0372     if (rc < 0)
0373         goto error_chip;
0374 
0375     pcm->info_flags = 0;
0376     pcm->private_data = chip;
0377     strscpy(pcm->name, "Trident TM5600/60x0", sizeof(pcm->name));
0378 
0379     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
0380     snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
0381 
0382     INIT_WORK(&dev->wq_trigger, audio_trigger);
0383     rc = snd_card_register(card);
0384     if (rc < 0)
0385         goto error_chip;
0386 
0387     dprintk(1, "Registered audio driver for %s\n", card->longname);
0388 
0389     return 0;
0390 
0391 error_chip:
0392     kfree(chip);
0393     dev->adev = NULL;
0394 error:
0395     snd_card_free(card);
0396     return rc;
0397 }
0398 
0399 static int tm6000_audio_fini(struct tm6000_core *dev)
0400 {
0401     struct snd_tm6000_card *chip;
0402 
0403     if (!dev)
0404         return 0;
0405     chip = dev->adev;
0406 
0407     if (!chip)
0408         return 0;
0409 
0410     if (!chip->card)
0411         return 0;
0412 
0413     snd_card_free(chip->card);
0414     chip->card = NULL;
0415     kfree(chip);
0416     dev->adev = NULL;
0417 
0418     return 0;
0419 }
0420 
0421 static struct tm6000_ops audio_ops = {
0422     .type   = TM6000_AUDIO,
0423     .name   = "TM6000 Audio Extension",
0424     .init   = tm6000_audio_init,
0425     .fini   = tm6000_audio_fini,
0426     .fillbuf = tm6000_fillbuf,
0427 };
0428 
0429 static int __init tm6000_alsa_register(void)
0430 {
0431     return tm6000_register_extension(&audio_ops);
0432 }
0433 
0434 static void __exit tm6000_alsa_unregister(void)
0435 {
0436     tm6000_unregister_extension(&audio_ops);
0437 }
0438 
0439 module_init(tm6000_alsa_register);
0440 module_exit(tm6000_alsa_unregister);