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

budget-core.c (17131B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * budget-core.c: driver for the SAA7146 based Budget DVB cards
      4 *
      5 * Compiled from various sources by Michael Hunold <michael@mihu.de>
      6 *
      7 * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
      8 *
      9 * Copyright (C) 1999-2002 Ralph  Metzler
     10 *			 & Marcus Metzler for convergence integrated media GmbH
     11 *
     12 * 26feb2004 Support for FS Activy Card (Grundig tuner) by
     13 *	     Michael Dreher <michael@5dot1.de>,
     14 *	     Oliver Endriss <o.endriss@gmx.de>,
     15 *	     Andreas 'randy' Weinberger
     16 *
     17 * the project's page is at https://linuxtv.org
     18 */
     19
     20
     21#include "budget.h"
     22#include "ttpci-eeprom.h"
     23
     24#define TS_WIDTH		(2 * TS_SIZE)
     25#define TS_WIDTH_ACTIVY		TS_SIZE
     26#define TS_WIDTH_DVBC		TS_SIZE
     27#define TS_HEIGHT_MASK		0xf00
     28#define TS_HEIGHT_MASK_ACTIVY	0xc00
     29#define TS_HEIGHT_MASK_DVBC	0xe00
     30#define TS_MIN_BUFSIZE_K	188
     31#define TS_MAX_BUFSIZE_K	1410
     32#define TS_MAX_BUFSIZE_K_ACTIVY	564
     33#define TS_MAX_BUFSIZE_K_DVBC	1316
     34#define BUFFER_WARNING_WAIT	(30*HZ)
     35
     36int budget_debug;
     37static int dma_buffer_size = TS_MIN_BUFSIZE_K;
     38module_param_named(debug, budget_debug, int, 0644);
     39module_param_named(bufsize, dma_buffer_size, int, 0444);
     40MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
     41MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)");
     42
     43/****************************************************************************
     44 * TT budget / WinTV Nova
     45 ****************************************************************************/
     46
     47static int stop_ts_capture(struct budget *budget)
     48{
     49	dprintk(2, "budget: %p\n", budget);
     50
     51	saa7146_write(budget->dev, MC1, MASK_20);	// DMA3 off
     52	SAA7146_IER_DISABLE(budget->dev, MASK_10);
     53	return 0;
     54}
     55
     56static int start_ts_capture(struct budget *budget)
     57{
     58	struct saa7146_dev *dev = budget->dev;
     59
     60	dprintk(2, "budget: %p\n", budget);
     61
     62	if (!budget->feeding || !budget->fe_synced)
     63		return 0;
     64
     65	saa7146_write(dev, MC1, MASK_20);	// DMA3 off
     66
     67	memset(budget->grabbing, 0x00, budget->buffer_size);
     68
     69	saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
     70
     71	budget->ttbp = 0;
     72
     73	/*
     74	 *  Signal path on the Activy:
     75	 *
     76	 *  tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory
     77	 *
     78	 *  Since the tuner feeds 204 bytes packets into the SAA7146,
     79	 *  DMA3 is configured to strip the trailing 16 FEC bytes:
     80	 *      Pitch: 188, NumBytes3: 188, NumLines3: 1024
     81	 */
     82
     83	switch(budget->card->type) {
     84	case BUDGET_FS_ACTIVY:
     85		saa7146_write(dev, DD1_INIT, 0x04000000);
     86		saa7146_write(dev, MC2, (MASK_09 | MASK_25));
     87		saa7146_write(dev, BRS_CTRL, 0x00000000);
     88		break;
     89	case BUDGET_PATCH:
     90		saa7146_write(dev, DD1_INIT, 0x00000200);
     91		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
     92		saa7146_write(dev, BRS_CTRL, 0x60000000);
     93		break;
     94	case BUDGET_CIN1200C_MK3:
     95	case BUDGET_KNC1C_MK3:
     96	case BUDGET_KNC1C_TDA10024:
     97	case BUDGET_KNC1CP_MK3:
     98		if (budget->video_port == BUDGET_VIDEO_PORTA) {
     99			saa7146_write(dev, DD1_INIT, 0x06000200);
    100			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
    101			saa7146_write(dev, BRS_CTRL, 0x00000000);
    102		} else {
    103			saa7146_write(dev, DD1_INIT, 0x00000600);
    104			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
    105			saa7146_write(dev, BRS_CTRL, 0x60000000);
    106		}
    107		break;
    108	default:
    109		if (budget->video_port == BUDGET_VIDEO_PORTA) {
    110			saa7146_write(dev, DD1_INIT, 0x06000200);
    111			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
    112			saa7146_write(dev, BRS_CTRL, 0x00000000);
    113		} else {
    114			saa7146_write(dev, DD1_INIT, 0x02000600);
    115			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
    116			saa7146_write(dev, BRS_CTRL, 0x60000000);
    117		}
    118	}
    119
    120	saa7146_write(dev, MC2, (MASK_08 | MASK_24));
    121	mdelay(10);
    122
    123	saa7146_write(dev, BASE_ODD3, 0);
    124	if (budget->buffer_size > budget->buffer_height * budget->buffer_width) {
    125		// using odd/even buffers
    126		saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width);
    127	} else {
    128		// using a single buffer
    129		saa7146_write(dev, BASE_EVEN3, 0);
    130	}
    131	saa7146_write(dev, PROT_ADDR3, budget->buffer_size);
    132	saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
    133
    134	saa7146_write(dev, PITCH3, budget->buffer_width);
    135	saa7146_write(dev, NUM_LINE_BYTE3,
    136			(budget->buffer_height << 16) | budget->buffer_width);
    137
    138	saa7146_write(dev, MC2, (MASK_04 | MASK_20));
    139
    140	SAA7146_ISR_CLEAR(budget->dev, MASK_10);	/* VPE */
    141	SAA7146_IER_ENABLE(budget->dev, MASK_10);	/* VPE */
    142	saa7146_write(dev, MC1, (MASK_04 | MASK_20));	/* DMA3 on */
    143
    144	return 0;
    145}
    146
    147static int budget_read_fe_status(struct dvb_frontend *fe,
    148				 enum fe_status *status)
    149{
    150	struct budget *budget = (struct budget *) fe->dvb->priv;
    151	int synced;
    152	int ret;
    153
    154	if (budget->read_fe_status)
    155		ret = budget->read_fe_status(fe, status);
    156	else
    157		ret = -EINVAL;
    158
    159	if (!ret) {
    160		synced = (*status & FE_HAS_LOCK);
    161		if (synced != budget->fe_synced) {
    162			budget->fe_synced = synced;
    163			spin_lock(&budget->feedlock);
    164			if (synced)
    165				start_ts_capture(budget);
    166			else
    167				stop_ts_capture(budget);
    168			spin_unlock(&budget->feedlock);
    169		}
    170	}
    171	return ret;
    172}
    173
    174static void vpeirq(struct tasklet_struct *t)
    175{
    176	struct budget *budget = from_tasklet(budget, t, vpe_tasklet);
    177	u8 *mem = (u8 *) (budget->grabbing);
    178	u32 olddma = budget->ttbp;
    179	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
    180	u32 count;
    181
    182	/* Ensure streamed PCI data is synced to CPU */
    183	dma_sync_sg_for_cpu(&budget->dev->pci->dev, budget->pt.slist,
    184			    budget->pt.nents, DMA_FROM_DEVICE);
    185
    186	/* nearest lower position divisible by 188 */
    187	newdma -= newdma % 188;
    188
    189	if (newdma >= budget->buffer_size)
    190		return;
    191
    192	budget->ttbp = newdma;
    193
    194	if (budget->feeding == 0 || newdma == olddma)
    195		return;
    196
    197	if (newdma > olddma) {	/* no wraparound, dump olddma..newdma */
    198		count = newdma - olddma;
    199		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188);
    200	} else {		/* wraparound, dump olddma..buflen and 0..newdma */
    201		count = budget->buffer_size - olddma;
    202		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188);
    203		count += newdma;
    204		dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188);
    205	}
    206
    207	if (count > budget->buffer_warning_threshold)
    208		budget->buffer_warnings++;
    209
    210	if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) {
    211		printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n",
    212			budget->dev->name, __func__, budget->buffer_warnings, count);
    213		budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT;
    214		budget->buffer_warnings = 0;
    215	}
    216}
    217
    218
    219static int ttpci_budget_debiread_nolock(struct budget *budget, u32 config,
    220		int addr, int count, int nobusyloop)
    221{
    222	struct saa7146_dev *saa = budget->dev;
    223	int result;
    224
    225	result = saa7146_wait_for_debi_done(saa, nobusyloop);
    226	if (result < 0)
    227		return result;
    228
    229	saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
    230	saa7146_write(saa, DEBI_CONFIG, config);
    231	saa7146_write(saa, DEBI_PAGE, 0);
    232	saa7146_write(saa, MC2, (2 << 16) | 2);
    233
    234	result = saa7146_wait_for_debi_done(saa, nobusyloop);
    235	if (result < 0)
    236		return result;
    237
    238	result = saa7146_read(saa, DEBI_AD);
    239	result &= (0xffffffffUL >> ((4 - count) * 8));
    240	return result;
    241}
    242
    243int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
    244			  int uselocks, int nobusyloop)
    245{
    246	if (count > 4 || count <= 0)
    247		return 0;
    248
    249	if (uselocks) {
    250		unsigned long flags;
    251		int result;
    252
    253		spin_lock_irqsave(&budget->debilock, flags);
    254		result = ttpci_budget_debiread_nolock(budget, config, addr,
    255						      count, nobusyloop);
    256		spin_unlock_irqrestore(&budget->debilock, flags);
    257		return result;
    258	}
    259	return ttpci_budget_debiread_nolock(budget, config, addr,
    260					    count, nobusyloop);
    261}
    262
    263static int ttpci_budget_debiwrite_nolock(struct budget *budget, u32 config,
    264		int addr, int count, u32 value, int nobusyloop)
    265{
    266	struct saa7146_dev *saa = budget->dev;
    267	int result;
    268
    269	result = saa7146_wait_for_debi_done(saa, nobusyloop);
    270	if (result < 0)
    271		return result;
    272
    273	saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff));
    274	saa7146_write(saa, DEBI_CONFIG, config);
    275	saa7146_write(saa, DEBI_PAGE, 0);
    276	saa7146_write(saa, DEBI_AD, value);
    277	saa7146_write(saa, MC2, (2 << 16) | 2);
    278
    279	result = saa7146_wait_for_debi_done(saa, nobusyloop);
    280	return result < 0 ? result : 0;
    281}
    282
    283int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
    284			   int count, u32 value, int uselocks, int nobusyloop)
    285{
    286	if (count > 4 || count <= 0)
    287		return 0;
    288
    289	if (uselocks) {
    290		unsigned long flags;
    291		int result;
    292
    293		spin_lock_irqsave(&budget->debilock, flags);
    294		result = ttpci_budget_debiwrite_nolock(budget, config, addr,
    295						count, value, nobusyloop);
    296		spin_unlock_irqrestore(&budget->debilock, flags);
    297		return result;
    298	}
    299	return ttpci_budget_debiwrite_nolock(budget, config, addr,
    300					     count, value, nobusyloop);
    301}
    302
    303
    304/****************************************************************************
    305 * DVB API SECTION
    306 ****************************************************************************/
    307
    308static int budget_start_feed(struct dvb_demux_feed *feed)
    309{
    310	struct dvb_demux *demux = feed->demux;
    311	struct budget *budget = (struct budget *) demux->priv;
    312	int status = 0;
    313
    314	dprintk(2, "budget: %p\n", budget);
    315
    316	if (!demux->dmx.frontend)
    317		return -EINVAL;
    318
    319	spin_lock(&budget->feedlock);
    320	feed->pusi_seen = false; /* have a clean section start */
    321	if (budget->feeding++ == 0)
    322		status = start_ts_capture(budget);
    323	spin_unlock(&budget->feedlock);
    324	return status;
    325}
    326
    327static int budget_stop_feed(struct dvb_demux_feed *feed)
    328{
    329	struct dvb_demux *demux = feed->demux;
    330	struct budget *budget = (struct budget *) demux->priv;
    331	int status = 0;
    332
    333	dprintk(2, "budget: %p\n", budget);
    334
    335	spin_lock(&budget->feedlock);
    336	if (--budget->feeding == 0)
    337		status = stop_ts_capture(budget);
    338	spin_unlock(&budget->feedlock);
    339	return status;
    340}
    341
    342static int budget_register(struct budget *budget)
    343{
    344	struct dvb_demux *dvbdemux = &budget->demux;
    345	int ret;
    346
    347	dprintk(2, "budget: %p\n", budget);
    348
    349	dvbdemux->priv = (void *) budget;
    350
    351	dvbdemux->filternum = 256;
    352	dvbdemux->feednum = 256;
    353	dvbdemux->start_feed = budget_start_feed;
    354	dvbdemux->stop_feed = budget_stop_feed;
    355	dvbdemux->write_to_decoder = NULL;
    356
    357	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
    358				      DMX_MEMORY_BASED_FILTERING);
    359
    360	dvb_dmx_init(&budget->demux);
    361
    362	budget->dmxdev.filternum = 256;
    363	budget->dmxdev.demux = &dvbdemux->dmx;
    364	budget->dmxdev.capabilities = 0;
    365
    366	dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter);
    367
    368	budget->hw_frontend.source = DMX_FRONTEND_0;
    369
    370	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend);
    371
    372	if (ret < 0)
    373		goto err_release_dmx;
    374
    375	budget->mem_frontend.source = DMX_MEMORY_FE;
    376	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
    377	if (ret < 0)
    378		goto err_release_dmx;
    379
    380	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
    381	if (ret < 0)
    382		goto err_release_dmx;
    383
    384	dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);
    385
    386	return 0;
    387
    388err_release_dmx:
    389	dvb_dmxdev_release(&budget->dmxdev);
    390	dvb_dmx_release(&budget->demux);
    391	return ret;
    392}
    393
    394static void budget_unregister(struct budget *budget)
    395{
    396	struct dvb_demux *dvbdemux = &budget->demux;
    397
    398	dprintk(2, "budget: %p\n", budget);
    399
    400	dvb_net_release(&budget->dvb_net);
    401
    402	dvbdemux->dmx.close(&dvbdemux->dmx);
    403	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend);
    404	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend);
    405
    406	dvb_dmxdev_release(&budget->dmxdev);
    407	dvb_dmx_release(&budget->demux);
    408}
    409
    410int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
    411		      struct saa7146_pci_extension_data *info,
    412		      struct module *owner, short *adapter_nums)
    413{
    414	int ret = 0;
    415	struct budget_info *bi = info->ext_priv;
    416	int max_bufsize;
    417	int height_mask;
    418
    419	memset(budget, 0, sizeof(struct budget));
    420
    421	dprintk(2, "dev: %p, budget: %p\n", dev, budget);
    422
    423	budget->card = bi;
    424	budget->dev = (struct saa7146_dev *) dev;
    425
    426	switch(budget->card->type) {
    427	case BUDGET_FS_ACTIVY:
    428		budget->buffer_width = TS_WIDTH_ACTIVY;
    429		max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY;
    430		height_mask = TS_HEIGHT_MASK_ACTIVY;
    431		break;
    432
    433	case BUDGET_KNC1C:
    434	case BUDGET_KNC1CP:
    435	case BUDGET_CIN1200C:
    436	case BUDGET_KNC1C_MK3:
    437	case BUDGET_KNC1C_TDA10024:
    438	case BUDGET_KNC1CP_MK3:
    439	case BUDGET_CIN1200C_MK3:
    440		budget->buffer_width = TS_WIDTH_DVBC;
    441		max_bufsize = TS_MAX_BUFSIZE_K_DVBC;
    442		height_mask = TS_HEIGHT_MASK_DVBC;
    443		break;
    444
    445	default:
    446		budget->buffer_width = TS_WIDTH;
    447		max_bufsize = TS_MAX_BUFSIZE_K;
    448		height_mask = TS_HEIGHT_MASK;
    449	}
    450
    451	if (dma_buffer_size < TS_MIN_BUFSIZE_K)
    452		dma_buffer_size = TS_MIN_BUFSIZE_K;
    453	else if (dma_buffer_size > max_bufsize)
    454		dma_buffer_size = max_bufsize;
    455
    456	budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width;
    457	if (budget->buffer_height > 0xfff) {
    458		budget->buffer_height /= 2;
    459		budget->buffer_height &= height_mask;
    460		budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width;
    461	} else {
    462		budget->buffer_height &= height_mask;
    463		budget->buffer_size = budget->buffer_height * budget->buffer_width;
    464	}
    465	budget->buffer_warning_threshold = budget->buffer_size * 80/100;
    466	budget->buffer_warnings = 0;
    467	budget->buffer_warning_time = jiffies;
    468
    469	dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n",
    470		budget->dev->name,
    471		budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single",
    472		budget->buffer_width, budget->buffer_height);
    473	printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
    474
    475	ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name,
    476				   owner, &budget->dev->pci->dev, adapter_nums);
    477	if (ret < 0)
    478		return ret;
    479
    480	/* set dd1 stream a & b */
    481	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
    482	saa7146_write(dev, MC2, (MASK_09 | MASK_25));
    483	saa7146_write(dev, MC2, (MASK_10 | MASK_26));
    484	saa7146_write(dev, DD1_INIT, 0x02000000);
    485	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
    486
    487	if (bi->type != BUDGET_FS_ACTIVY)
    488		budget->video_port = BUDGET_VIDEO_PORTB;
    489	else
    490		budget->video_port = BUDGET_VIDEO_PORTA;
    491	spin_lock_init(&budget->feedlock);
    492	spin_lock_init(&budget->debilock);
    493
    494	/* the Siemens DVB needs this if you want to have the i2c chips
    495	   get recognized before the main driver is loaded */
    496	if (bi->type != BUDGET_FS_ACTIVY)
    497		saa7146_write(dev, GPIO_CTRL, 0x500000);	/* GPIO 3 = 1 */
    498
    499	strscpy(budget->i2c_adap.name, budget->card->name,
    500		sizeof(budget->i2c_adap.name));
    501
    502	saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
    503	strscpy(budget->i2c_adap.name, budget->card->name,
    504		sizeof(budget->i2c_adap.name));
    505
    506	if (i2c_add_adapter(&budget->i2c_adap) < 0) {
    507		ret = -ENOMEM;
    508		goto err_dvb_unregister;
    509	}
    510
    511	ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac);
    512
    513	budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt);
    514	if (NULL == budget->grabbing) {
    515		ret = -ENOMEM;
    516		goto err_del_i2c;
    517	}
    518
    519	saa7146_write(dev, PCI_BT_V1, 0x001c0000);
    520	/* upload all */
    521	saa7146_write(dev, GPIO_CTRL, 0x000000);
    522
    523	tasklet_setup(&budget->vpe_tasklet, vpeirq);
    524
    525	/* frontend power on */
    526	if (bi->type != BUDGET_FS_ACTIVY)
    527		saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
    528
    529	if ((ret = budget_register(budget)) == 0)
    530		return 0; /* Everything OK */
    531
    532	/* An error occurred, cleanup resources */
    533	saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
    534
    535err_del_i2c:
    536	i2c_del_adapter(&budget->i2c_adap);
    537
    538err_dvb_unregister:
    539	dvb_unregister_adapter(&budget->dvb_adapter);
    540
    541	return ret;
    542}
    543
    544void ttpci_budget_init_hooks(struct budget *budget)
    545{
    546	if (budget->dvb_frontend && !budget->read_fe_status) {
    547		budget->read_fe_status = budget->dvb_frontend->ops.read_status;
    548		budget->dvb_frontend->ops.read_status = budget_read_fe_status;
    549	}
    550}
    551
    552int ttpci_budget_deinit(struct budget *budget)
    553{
    554	struct saa7146_dev *dev = budget->dev;
    555
    556	dprintk(2, "budget: %p\n", budget);
    557
    558	budget_unregister(budget);
    559
    560	tasklet_kill(&budget->vpe_tasklet);
    561
    562	saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
    563
    564	i2c_del_adapter(&budget->i2c_adap);
    565
    566	dvb_unregister_adapter(&budget->dvb_adapter);
    567
    568	return 0;
    569}
    570
    571void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr)
    572{
    573	struct budget *budget = (struct budget *) dev->ext_priv;
    574
    575	dprintk(8, "dev: %p, budget: %p\n", dev, budget);
    576
    577	if (*isr & MASK_10)
    578		tasklet_schedule(&budget->vpe_tasklet);
    579}
    580
    581void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
    582{
    583	struct budget *budget = (struct budget *) dev->ext_priv;
    584
    585	spin_lock(&budget->feedlock);
    586	budget->video_port = video_port;
    587	if (budget->feeding) {
    588		stop_ts_capture(budget);
    589		start_ts_capture(budget);
    590	}
    591	spin_unlock(&budget->feedlock);
    592}
    593
    594EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
    595EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
    596EXPORT_SYMBOL_GPL(ttpci_budget_init);
    597EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks);
    598EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
    599EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
    600EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
    601EXPORT_SYMBOL_GPL(budget_debug);
    602
    603MODULE_LICENSE("GPL");