| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Conexant Cx231xx audio extension |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2008 <srinivasa.deevi at conexant dot com> |
|---|
| 5 | 6 | * Based on em28xx driver |
|---|
| 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 | 7 | */ |
|---|
| 18 | 8 | |
|---|
| 19 | 9 | #include "cx231xx.h" |
|---|
| .. | .. |
|---|
| 23 | 13 | #include <linux/spinlock.h> |
|---|
| 24 | 14 | #include <linux/soundcard.h> |
|---|
| 25 | 15 | #include <linux/slab.h> |
|---|
| 26 | | -#include <linux/vmalloc.h> |
|---|
| 27 | | -#include <linux/proc_fs.h> |
|---|
| 28 | 16 | #include <linux/module.h> |
|---|
| 29 | 17 | #include <sound/core.h> |
|---|
| 30 | 18 | #include <sound/pcm.h> |
|---|
| .. | .. |
|---|
| 383 | 371 | return errCode; |
|---|
| 384 | 372 | } |
|---|
| 385 | 373 | |
|---|
| 386 | | -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, |
|---|
| 387 | | - size_t size) |
|---|
| 388 | | -{ |
|---|
| 389 | | - struct snd_pcm_runtime *runtime = subs->runtime; |
|---|
| 390 | | - struct cx231xx *dev = snd_pcm_substream_chip(subs); |
|---|
| 391 | | - |
|---|
| 392 | | - dev_dbg(dev->dev, "Allocating vbuffer\n"); |
|---|
| 393 | | - if (runtime->dma_area) { |
|---|
| 394 | | - if (runtime->dma_bytes > size) |
|---|
| 395 | | - return 0; |
|---|
| 396 | | - |
|---|
| 397 | | - vfree(runtime->dma_area); |
|---|
| 398 | | - } |
|---|
| 399 | | - runtime->dma_area = vmalloc(size); |
|---|
| 400 | | - if (!runtime->dma_area) |
|---|
| 401 | | - return -ENOMEM; |
|---|
| 402 | | - |
|---|
| 403 | | - runtime->dma_bytes = size; |
|---|
| 404 | | - |
|---|
| 405 | | - return 0; |
|---|
| 406 | | -} |
|---|
| 407 | | - |
|---|
| 408 | 374 | static const struct snd_pcm_hardware snd_cx231xx_hw_capture = { |
|---|
| 409 | 375 | .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | |
|---|
| 410 | 376 | SNDRV_PCM_INFO_MMAP | |
|---|
| .. | .. |
|---|
| 495 | 461 | } |
|---|
| 496 | 462 | |
|---|
| 497 | 463 | dev->adev.users--; |
|---|
| 498 | | - if (substream->runtime->dma_area) { |
|---|
| 499 | | - dev_dbg(dev->dev, "freeing\n"); |
|---|
| 500 | | - vfree(substream->runtime->dma_area); |
|---|
| 501 | | - substream->runtime->dma_area = NULL; |
|---|
| 502 | | - } |
|---|
| 503 | 464 | mutex_unlock(&dev->lock); |
|---|
| 504 | 465 | |
|---|
| 505 | 466 | if (dev->adev.users == 0 && dev->adev.shutdown == 1) { |
|---|
| .. | .. |
|---|
| 512 | 473 | schedule_work(&dev->wq_trigger); |
|---|
| 513 | 474 | } |
|---|
| 514 | 475 | } |
|---|
| 515 | | - return 0; |
|---|
| 516 | | -} |
|---|
| 517 | | - |
|---|
| 518 | | -static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream, |
|---|
| 519 | | - struct snd_pcm_hw_params *hw_params) |
|---|
| 520 | | -{ |
|---|
| 521 | | - struct cx231xx *dev = snd_pcm_substream_chip(substream); |
|---|
| 522 | | - int ret; |
|---|
| 523 | | - |
|---|
| 524 | | - dev_dbg(dev->dev, "Setting capture parameters\n"); |
|---|
| 525 | | - |
|---|
| 526 | | - ret = snd_pcm_alloc_vmalloc_buffer(substream, |
|---|
| 527 | | - params_buffer_bytes(hw_params)); |
|---|
| 528 | | -#if 0 |
|---|
| 529 | | - /* TODO: set up cx231xx audio chip to deliver the correct audio format, |
|---|
| 530 | | - current default is 48000hz multiplexed => 96000hz mono |
|---|
| 531 | | - which shouldn't matter since analogue TV only supports mono */ |
|---|
| 532 | | - unsigned int channels, rate, format; |
|---|
| 533 | | - |
|---|
| 534 | | - format = params_format(hw_params); |
|---|
| 535 | | - rate = params_rate(hw_params); |
|---|
| 536 | | - channels = params_channels(hw_params); |
|---|
| 537 | | -#endif |
|---|
| 538 | | - |
|---|
| 539 | | - return ret; |
|---|
| 540 | | -} |
|---|
| 541 | | - |
|---|
| 542 | | -static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream) |
|---|
| 543 | | -{ |
|---|
| 544 | | - struct cx231xx *dev = snd_pcm_substream_chip(substream); |
|---|
| 545 | | - |
|---|
| 546 | | - dev_dbg(dev->dev, "Stop capture, if needed\n"); |
|---|
| 547 | | - |
|---|
| 548 | | - if (atomic_read(&dev->stream_started) > 0) { |
|---|
| 549 | | - atomic_set(&dev->stream_started, 0); |
|---|
| 550 | | - schedule_work(&dev->wq_trigger); |
|---|
| 551 | | - } |
|---|
| 552 | | - |
|---|
| 553 | 476 | return 0; |
|---|
| 554 | 477 | } |
|---|
| 555 | 478 | |
|---|
| .. | .. |
|---|
| 625 | 548 | return hwptr_done; |
|---|
| 626 | 549 | } |
|---|
| 627 | 550 | |
|---|
| 628 | | -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, |
|---|
| 629 | | - unsigned long offset) |
|---|
| 630 | | -{ |
|---|
| 631 | | - void *pageptr = subs->runtime->dma_area + offset; |
|---|
| 632 | | - |
|---|
| 633 | | - return vmalloc_to_page(pageptr); |
|---|
| 634 | | -} |
|---|
| 635 | | - |
|---|
| 636 | 551 | static const struct snd_pcm_ops snd_cx231xx_pcm_capture = { |
|---|
| 637 | 552 | .open = snd_cx231xx_capture_open, |
|---|
| 638 | 553 | .close = snd_cx231xx_pcm_close, |
|---|
| 639 | | - .ioctl = snd_pcm_lib_ioctl, |
|---|
| 640 | | - .hw_params = snd_cx231xx_hw_capture_params, |
|---|
| 641 | | - .hw_free = snd_cx231xx_hw_capture_free, |
|---|
| 642 | 554 | .prepare = snd_cx231xx_prepare, |
|---|
| 643 | 555 | .trigger = snd_cx231xx_capture_trigger, |
|---|
| 644 | 556 | .pointer = snd_cx231xx_capture_pointer, |
|---|
| 645 | | - .page = snd_pcm_get_vmalloc_page, |
|---|
| 646 | 557 | }; |
|---|
| 647 | 558 | |
|---|
| 648 | 559 | static int cx231xx_audio_init(struct cx231xx *dev) |
|---|
| .. | .. |
|---|
| 677 | 588 | |
|---|
| 678 | 589 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, |
|---|
| 679 | 590 | &snd_cx231xx_pcm_capture); |
|---|
| 591 | + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); |
|---|
| 680 | 592 | pcm->info_flags = 0; |
|---|
| 681 | 593 | pcm->private_data = dev; |
|---|
| 682 | | - strcpy(pcm->name, "Conexant cx231xx Capture"); |
|---|
| 683 | | - strcpy(card->driver, "Cx231xx-Audio"); |
|---|
| 684 | | - strcpy(card->shortname, "Cx231xx Audio"); |
|---|
| 685 | | - strcpy(card->longname, "Conexant cx231xx Audio"); |
|---|
| 594 | + strscpy(pcm->name, "Conexant cx231xx Capture", sizeof(pcm->name)); |
|---|
| 595 | + strscpy(card->driver, "Cx231xx-Audio", sizeof(card->driver)); |
|---|
| 596 | + strscpy(card->shortname, "Cx231xx Audio", sizeof(card->shortname)); |
|---|
| 597 | + strscpy(card->longname, "Conexant cx231xx Audio", sizeof(card->longname)); |
|---|
| 686 | 598 | |
|---|
| 687 | 599 | INIT_WORK(&dev->wq_trigger, audio_trigger); |
|---|
| 688 | 600 | |
|---|