cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

usbtv-audio.c (9962B)


      1/*
      2 * Copyright (c) 2013 Federico Simoncelli
      3 * All rights reserved.
      4 *
      5 * Redistribution and use in source and binary forms, with or without
      6 * modification, are permitted provided that the following conditions
      7 * are met:
      8 * 1. Redistributions of source code must retain the above copyright
      9 *    notice, this list of conditions, and the following disclaimer,
     10 *    without modification.
     11 * 2. The name of the author may not be used to endorse or promote products
     12 *    derived from this software without specific prior written permission.
     13 *
     14 * Alternatively, this software may be distributed under the terms of the
     15 * GNU General Public License ("GPL").
     16 *
     17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 */
     29/*
     30 * Fushicai USBTV007 Audio-Video Grabber Driver
     31 *
     32 * Product web site:
     33 * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
     34 *
     35 * No physical hardware was harmed running Windows during the
     36 * reverse-engineering activity
     37 */
     38
     39#include <sound/core.h>
     40#include <sound/initval.h>
     41#include <sound/ac97_codec.h>
     42#include <sound/pcm_params.h>
     43
     44#include "usbtv.h"
     45
     46static const struct snd_pcm_hardware snd_usbtv_digital_hw = {
     47	.info = SNDRV_PCM_INFO_BATCH |
     48		SNDRV_PCM_INFO_MMAP |
     49		SNDRV_PCM_INFO_INTERLEAVED |
     50		SNDRV_PCM_INFO_BLOCK_TRANSFER |
     51		SNDRV_PCM_INFO_MMAP_VALID,
     52	.formats = SNDRV_PCM_FMTBIT_S16_LE,
     53	.rates = SNDRV_PCM_RATE_48000,
     54	.rate_min = 48000,
     55	.rate_max = 48000,
     56	.channels_min = 2,
     57	.channels_max = 2,
     58	.period_bytes_min = 11059,
     59	.period_bytes_max = 13516,
     60	.periods_min = 2,
     61	.periods_max = 98,
     62	.buffer_bytes_max = 62720 * 8, /* value in usbaudio.c */
     63};
     64
     65static int snd_usbtv_pcm_open(struct snd_pcm_substream *substream)
     66{
     67	struct usbtv *chip = snd_pcm_substream_chip(substream);
     68	struct snd_pcm_runtime *runtime = substream->runtime;
     69
     70	chip->snd_substream = substream;
     71	runtime->hw = snd_usbtv_digital_hw;
     72
     73	return 0;
     74}
     75
     76static int snd_usbtv_pcm_close(struct snd_pcm_substream *substream)
     77{
     78	struct usbtv *chip = snd_pcm_substream_chip(substream);
     79
     80	if (atomic_read(&chip->snd_stream)) {
     81		atomic_set(&chip->snd_stream, 0);
     82		schedule_work(&chip->snd_trigger);
     83	}
     84
     85	return 0;
     86}
     87
     88static int snd_usbtv_prepare(struct snd_pcm_substream *substream)
     89{
     90	struct usbtv *chip = snd_pcm_substream_chip(substream);
     91
     92	chip->snd_buffer_pos = 0;
     93	chip->snd_period_pos = 0;
     94
     95	return 0;
     96}
     97
     98static void usbtv_audio_urb_received(struct urb *urb)
     99{
    100	struct usbtv *chip = urb->context;
    101	struct snd_pcm_substream *substream = chip->snd_substream;
    102	struct snd_pcm_runtime *runtime = substream->runtime;
    103	size_t i, frame_bytes, chunk_length, buffer_pos, period_pos;
    104	int period_elapsed;
    105	unsigned long flags;
    106	void *urb_current;
    107
    108	switch (urb->status) {
    109	case 0:
    110	case -ETIMEDOUT:
    111		break;
    112	case -ENOENT:
    113	case -EPROTO:
    114	case -ECONNRESET:
    115	case -ESHUTDOWN:
    116		return;
    117	default:
    118		dev_warn(chip->dev, "unknown audio urb status %i\n",
    119			urb->status);
    120	}
    121
    122	if (!atomic_read(&chip->snd_stream))
    123		return;
    124
    125	frame_bytes = runtime->frame_bits >> 3;
    126	chunk_length = USBTV_CHUNK / frame_bytes;
    127
    128	buffer_pos = chip->snd_buffer_pos;
    129	period_pos = chip->snd_period_pos;
    130	period_elapsed = 0;
    131
    132	for (i = 0; i < urb->actual_length; i += USBTV_CHUNK_SIZE) {
    133		urb_current = urb->transfer_buffer + i + USBTV_AUDIO_HDRSIZE;
    134
    135		if (buffer_pos + chunk_length >= runtime->buffer_size) {
    136			size_t cnt = (runtime->buffer_size - buffer_pos) *
    137				frame_bytes;
    138			memcpy(runtime->dma_area + buffer_pos * frame_bytes,
    139				urb_current, cnt);
    140			memcpy(runtime->dma_area, urb_current + cnt,
    141				chunk_length * frame_bytes - cnt);
    142		} else {
    143			memcpy(runtime->dma_area + buffer_pos * frame_bytes,
    144				urb_current, chunk_length * frame_bytes);
    145		}
    146
    147		buffer_pos += chunk_length;
    148		period_pos += chunk_length;
    149
    150		if (buffer_pos >= runtime->buffer_size)
    151			buffer_pos -= runtime->buffer_size;
    152
    153		if (period_pos >= runtime->period_size) {
    154			period_pos -= runtime->period_size;
    155			period_elapsed = 1;
    156		}
    157	}
    158
    159	snd_pcm_stream_lock_irqsave(substream, flags);
    160
    161	chip->snd_buffer_pos = buffer_pos;
    162	chip->snd_period_pos = period_pos;
    163
    164	snd_pcm_stream_unlock_irqrestore(substream, flags);
    165
    166	if (period_elapsed)
    167		snd_pcm_period_elapsed(substream);
    168
    169	usb_submit_urb(urb, GFP_ATOMIC);
    170}
    171
    172static int usbtv_audio_start(struct usbtv *chip)
    173{
    174	unsigned int pipe;
    175	static const u16 setup[][2] = {
    176		/* These seem to enable the device. */
    177		{ USBTV_BASE + 0x0008, 0x0001 },
    178		{ USBTV_BASE + 0x01d0, 0x00ff },
    179		{ USBTV_BASE + 0x01d9, 0x0002 },
    180
    181		{ USBTV_BASE + 0x01da, 0x0013 },
    182		{ USBTV_BASE + 0x01db, 0x0012 },
    183		{ USBTV_BASE + 0x01e9, 0x0002 },
    184		{ USBTV_BASE + 0x01ec, 0x006c },
    185		{ USBTV_BASE + 0x0294, 0x0020 },
    186		{ USBTV_BASE + 0x0255, 0x00cf },
    187		{ USBTV_BASE + 0x0256, 0x0020 },
    188		{ USBTV_BASE + 0x01eb, 0x0030 },
    189		{ USBTV_BASE + 0x027d, 0x00a6 },
    190		{ USBTV_BASE + 0x0280, 0x0011 },
    191		{ USBTV_BASE + 0x0281, 0x0040 },
    192		{ USBTV_BASE + 0x0282, 0x0011 },
    193		{ USBTV_BASE + 0x0283, 0x0040 },
    194		{ 0xf891, 0x0010 },
    195
    196		/* this sets the input from composite */
    197		{ USBTV_BASE + 0x0284, 0x00aa },
    198	};
    199
    200	chip->snd_bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
    201	if (chip->snd_bulk_urb == NULL)
    202		goto err_alloc_urb;
    203
    204	pipe = usb_rcvbulkpipe(chip->udev, USBTV_AUDIO_ENDP);
    205
    206	chip->snd_bulk_urb->transfer_buffer = kzalloc(
    207		USBTV_AUDIO_URBSIZE, GFP_KERNEL);
    208	if (chip->snd_bulk_urb->transfer_buffer == NULL)
    209		goto err_transfer_buffer;
    210
    211	usb_fill_bulk_urb(chip->snd_bulk_urb, chip->udev, pipe,
    212		chip->snd_bulk_urb->transfer_buffer, USBTV_AUDIO_URBSIZE,
    213		usbtv_audio_urb_received, chip);
    214
    215	/* starting the stream */
    216	usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
    217
    218	usb_clear_halt(chip->udev, pipe);
    219	usb_submit_urb(chip->snd_bulk_urb, GFP_ATOMIC);
    220
    221	return 0;
    222
    223err_transfer_buffer:
    224	usb_free_urb(chip->snd_bulk_urb);
    225	chip->snd_bulk_urb = NULL;
    226
    227err_alloc_urb:
    228	return -ENOMEM;
    229}
    230
    231static int usbtv_audio_stop(struct usbtv *chip)
    232{
    233	static const u16 setup[][2] = {
    234	/* The original windows driver sometimes sends also:
    235	 *   { USBTV_BASE + 0x00a2, 0x0013 }
    236	 * but it seems useless and its real effects are untested at
    237	 * the moment.
    238	 */
    239		{ USBTV_BASE + 0x027d, 0x0000 },
    240		{ USBTV_BASE + 0x0280, 0x0010 },
    241		{ USBTV_BASE + 0x0282, 0x0010 },
    242	};
    243
    244	if (chip->snd_bulk_urb) {
    245		usb_kill_urb(chip->snd_bulk_urb);
    246		kfree(chip->snd_bulk_urb->transfer_buffer);
    247		usb_free_urb(chip->snd_bulk_urb);
    248		chip->snd_bulk_urb = NULL;
    249	}
    250
    251	usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
    252
    253	return 0;
    254}
    255
    256void usbtv_audio_suspend(struct usbtv *usbtv)
    257{
    258	if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
    259		usb_kill_urb(usbtv->snd_bulk_urb);
    260}
    261
    262void usbtv_audio_resume(struct usbtv *usbtv)
    263{
    264	if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
    265		usb_submit_urb(usbtv->snd_bulk_urb, GFP_ATOMIC);
    266}
    267
    268static void snd_usbtv_trigger(struct work_struct *work)
    269{
    270	struct usbtv *chip = container_of(work, struct usbtv, snd_trigger);
    271
    272	if (!chip->snd)
    273		return;
    274
    275	if (atomic_read(&chip->snd_stream))
    276		usbtv_audio_start(chip);
    277	else
    278		usbtv_audio_stop(chip);
    279}
    280
    281static int snd_usbtv_card_trigger(struct snd_pcm_substream *substream, int cmd)
    282{
    283	struct usbtv *chip = snd_pcm_substream_chip(substream);
    284
    285	switch (cmd) {
    286	case SNDRV_PCM_TRIGGER_START:
    287	case SNDRV_PCM_TRIGGER_RESUME:
    288	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    289		atomic_set(&chip->snd_stream, 1);
    290		break;
    291	case SNDRV_PCM_TRIGGER_STOP:
    292	case SNDRV_PCM_TRIGGER_SUSPEND:
    293	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    294		atomic_set(&chip->snd_stream, 0);
    295		break;
    296	default:
    297		return -EINVAL;
    298	}
    299
    300	schedule_work(&chip->snd_trigger);
    301
    302	return 0;
    303}
    304
    305static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream)
    306{
    307	struct usbtv *chip = snd_pcm_substream_chip(substream);
    308
    309	return chip->snd_buffer_pos;
    310}
    311
    312static const struct snd_pcm_ops snd_usbtv_pcm_ops = {
    313	.open = snd_usbtv_pcm_open,
    314	.close = snd_usbtv_pcm_close,
    315	.prepare = snd_usbtv_prepare,
    316	.trigger = snd_usbtv_card_trigger,
    317	.pointer = snd_usbtv_pointer,
    318};
    319
    320int usbtv_audio_init(struct usbtv *usbtv)
    321{
    322	int rv;
    323	struct snd_card *card;
    324	struct snd_pcm *pcm;
    325
    326	INIT_WORK(&usbtv->snd_trigger, snd_usbtv_trigger);
    327	atomic_set(&usbtv->snd_stream, 0);
    328
    329	rv = snd_card_new(&usbtv->udev->dev, SNDRV_DEFAULT_IDX1, "usbtv",
    330		THIS_MODULE, 0, &card);
    331	if (rv < 0)
    332		return rv;
    333
    334	strscpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver));
    335	strscpy(card->shortname, "usbtv", sizeof(card->shortname));
    336	snprintf(card->longname, sizeof(card->longname),
    337		"USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum,
    338		usbtv->udev->devnum);
    339
    340	snd_card_set_dev(card, usbtv->dev);
    341
    342	usbtv->snd = card;
    343
    344	rv = snd_pcm_new(card, "USBTV Audio", 0, 0, 1, &pcm);
    345	if (rv < 0)
    346		goto err;
    347
    348	strscpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name));
    349	pcm->info_flags = 0;
    350	pcm->private_data = usbtv;
    351
    352	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops);
    353	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
    354		NULL, USBTV_AUDIO_BUFFER, USBTV_AUDIO_BUFFER);
    355
    356	rv = snd_card_register(card);
    357	if (rv)
    358		goto err;
    359
    360	return 0;
    361
    362err:
    363	usbtv->snd = NULL;
    364	snd_card_free(card);
    365
    366	return rv;
    367}
    368
    369void usbtv_audio_free(struct usbtv *usbtv)
    370{
    371	cancel_work_sync(&usbtv->snd_trigger);
    372
    373	if (usbtv->snd && usbtv->udev) {
    374		snd_card_free_when_closed(usbtv->snd);
    375		usbtv->snd = NULL;
    376	}
    377}