Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * budget-core.c: driver for the SAA7146 based Budget DVB cards
0004  *
0005  * Compiled from various sources by Michael Hunold <michael@mihu.de>
0006  *
0007  * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
0008  *
0009  * Copyright (C) 1999-2002 Ralph  Metzler
0010  *           & Marcus Metzler for convergence integrated media GmbH
0011  *
0012  * 26feb2004 Support for FS Activy Card (Grundig tuner) by
0013  *       Michael Dreher <michael@5dot1.de>,
0014  *       Oliver Endriss <o.endriss@gmx.de>,
0015  *       Andreas 'randy' Weinberger
0016  *
0017  * the project's page is at https://linuxtv.org
0018  */
0019 
0020 
0021 #include "budget.h"
0022 #include "ttpci-eeprom.h"
0023 
0024 #define TS_WIDTH        (2 * TS_SIZE)
0025 #define TS_WIDTH_ACTIVY     TS_SIZE
0026 #define TS_WIDTH_DVBC       TS_SIZE
0027 #define TS_HEIGHT_MASK      0xf00
0028 #define TS_HEIGHT_MASK_ACTIVY   0xc00
0029 #define TS_HEIGHT_MASK_DVBC 0xe00
0030 #define TS_MIN_BUFSIZE_K    188
0031 #define TS_MAX_BUFSIZE_K    1410
0032 #define TS_MAX_BUFSIZE_K_ACTIVY 564
0033 #define TS_MAX_BUFSIZE_K_DVBC   1316
0034 #define BUFFER_WARNING_WAIT (30*HZ)
0035 
0036 int budget_debug;
0037 static int dma_buffer_size = TS_MIN_BUFSIZE_K;
0038 module_param_named(debug, budget_debug, int, 0644);
0039 module_param_named(bufsize, dma_buffer_size, int, 0444);
0040 MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
0041 MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)");
0042 
0043 /****************************************************************************
0044  * TT budget / WinTV Nova
0045  ****************************************************************************/
0046 
0047 static int stop_ts_capture(struct budget *budget)
0048 {
0049     dprintk(2, "budget: %p\n", budget);
0050 
0051     saa7146_write(budget->dev, MC1, MASK_20);   // DMA3 off
0052     SAA7146_IER_DISABLE(budget->dev, MASK_10);
0053     return 0;
0054 }
0055 
0056 static int start_ts_capture(struct budget *budget)
0057 {
0058     struct saa7146_dev *dev = budget->dev;
0059 
0060     dprintk(2, "budget: %p\n", budget);
0061 
0062     if (!budget->feeding || !budget->fe_synced)
0063         return 0;
0064 
0065     saa7146_write(dev, MC1, MASK_20);   // DMA3 off
0066 
0067     memset(budget->grabbing, 0x00, budget->buffer_size);
0068 
0069     saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
0070 
0071     budget->ttbp = 0;
0072 
0073     /*
0074      *  Signal path on the Activy:
0075      *
0076      *  tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory
0077      *
0078      *  Since the tuner feeds 204 bytes packets into the SAA7146,
0079      *  DMA3 is configured to strip the trailing 16 FEC bytes:
0080      *      Pitch: 188, NumBytes3: 188, NumLines3: 1024
0081      */
0082 
0083     switch(budget->card->type) {
0084     case BUDGET_FS_ACTIVY:
0085         saa7146_write(dev, DD1_INIT, 0x04000000);
0086         saa7146_write(dev, MC2, (MASK_09 | MASK_25));
0087         saa7146_write(dev, BRS_CTRL, 0x00000000);
0088         break;
0089     case BUDGET_PATCH:
0090         saa7146_write(dev, DD1_INIT, 0x00000200);
0091         saa7146_write(dev, MC2, (MASK_10 | MASK_26));
0092         saa7146_write(dev, BRS_CTRL, 0x60000000);
0093         break;
0094     case BUDGET_CIN1200C_MK3:
0095     case BUDGET_KNC1C_MK3:
0096     case BUDGET_KNC1C_TDA10024:
0097     case BUDGET_KNC1CP_MK3:
0098         if (budget->video_port == BUDGET_VIDEO_PORTA) {
0099             saa7146_write(dev, DD1_INIT, 0x06000200);
0100             saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
0101             saa7146_write(dev, BRS_CTRL, 0x00000000);
0102         } else {
0103             saa7146_write(dev, DD1_INIT, 0x00000600);
0104             saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
0105             saa7146_write(dev, BRS_CTRL, 0x60000000);
0106         }
0107         break;
0108     default:
0109         if (budget->video_port == BUDGET_VIDEO_PORTA) {
0110             saa7146_write(dev, DD1_INIT, 0x06000200);
0111             saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
0112             saa7146_write(dev, BRS_CTRL, 0x00000000);
0113         } else {
0114             saa7146_write(dev, DD1_INIT, 0x02000600);
0115             saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
0116             saa7146_write(dev, BRS_CTRL, 0x60000000);
0117         }
0118     }
0119 
0120     saa7146_write(dev, MC2, (MASK_08 | MASK_24));
0121     mdelay(10);
0122 
0123     saa7146_write(dev, BASE_ODD3, 0);
0124     if (budget->buffer_size > budget->buffer_height * budget->buffer_width) {
0125         // using odd/even buffers
0126         saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width);
0127     } else {
0128         // using a single buffer
0129         saa7146_write(dev, BASE_EVEN3, 0);
0130     }
0131     saa7146_write(dev, PROT_ADDR3, budget->buffer_size);
0132     saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
0133 
0134     saa7146_write(dev, PITCH3, budget->buffer_width);
0135     saa7146_write(dev, NUM_LINE_BYTE3,
0136             (budget->buffer_height << 16) | budget->buffer_width);
0137 
0138     saa7146_write(dev, MC2, (MASK_04 | MASK_20));
0139 
0140     SAA7146_ISR_CLEAR(budget->dev, MASK_10);    /* VPE */
0141     SAA7146_IER_ENABLE(budget->dev, MASK_10);   /* VPE */
0142     saa7146_write(dev, MC1, (MASK_04 | MASK_20));   /* DMA3 on */
0143 
0144     return 0;
0145 }
0146 
0147 static int budget_read_fe_status(struct dvb_frontend *fe,
0148                  enum fe_status *status)
0149 {
0150     struct budget *budget = (struct budget *) fe->dvb->priv;
0151     int synced;
0152     int ret;
0153 
0154     if (budget->read_fe_status)
0155         ret = budget->read_fe_status(fe, status);
0156     else
0157         ret = -EINVAL;
0158 
0159     if (!ret) {
0160         synced = (*status & FE_HAS_LOCK);
0161         if (synced != budget->fe_synced) {
0162             budget->fe_synced = synced;
0163             spin_lock(&budget->feedlock);
0164             if (synced)
0165                 start_ts_capture(budget);
0166             else
0167                 stop_ts_capture(budget);
0168             spin_unlock(&budget->feedlock);
0169         }
0170     }
0171     return ret;
0172 }
0173 
0174 static void vpeirq(struct tasklet_struct *t)
0175 {
0176     struct budget *budget = from_tasklet(budget, t, vpe_tasklet);
0177     u8 *mem = (u8 *) (budget->grabbing);
0178     u32 olddma = budget->ttbp;
0179     u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
0180     u32 count;
0181 
0182     /* Ensure streamed PCI data is synced to CPU */
0183     dma_sync_sg_for_cpu(&budget->dev->pci->dev, budget->pt.slist,
0184                 budget->pt.nents, DMA_FROM_DEVICE);
0185 
0186     /* nearest lower position divisible by 188 */
0187     newdma -= newdma % 188;
0188 
0189     if (newdma >= budget->buffer_size)
0190         return;
0191 
0192     budget->ttbp = newdma;
0193 
0194     if (budget->feeding == 0 || newdma == olddma)
0195         return;
0196 
0197     if (newdma > olddma) {  /* no wraparound, dump olddma..newdma */
0198         count = newdma - olddma;
0199         dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188);
0200     } else {        /* wraparound, dump olddma..buflen and 0..newdma */
0201         count = budget->buffer_size - olddma;
0202         dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188);
0203         count += newdma;
0204         dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188);
0205     }
0206 
0207     if (count > budget->buffer_warning_threshold)
0208         budget->buffer_warnings++;
0209 
0210     if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) {
0211         printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n",
0212             budget->dev->name, __func__, budget->buffer_warnings, count);
0213         budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT;
0214         budget->buffer_warnings = 0;
0215     }
0216 }
0217 
0218 
0219 static int ttpci_budget_debiread_nolock(struct budget *budget, u32 config,
0220         int addr, int count, int nobusyloop)
0221 {
0222     struct saa7146_dev *saa = budget->dev;
0223     int result;
0224 
0225     result = saa7146_wait_for_debi_done(saa, nobusyloop);
0226     if (result < 0)
0227         return result;
0228 
0229     saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
0230     saa7146_write(saa, DEBI_CONFIG, config);
0231     saa7146_write(saa, DEBI_PAGE, 0);
0232     saa7146_write(saa, MC2, (2 << 16) | 2);
0233 
0234     result = saa7146_wait_for_debi_done(saa, nobusyloop);
0235     if (result < 0)
0236         return result;
0237 
0238     result = saa7146_read(saa, DEBI_AD);
0239     result &= (0xffffffffUL >> ((4 - count) * 8));
0240     return result;
0241 }
0242 
0243 int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
0244               int uselocks, int nobusyloop)
0245 {
0246     if (count > 4 || count <= 0)
0247         return 0;
0248 
0249     if (uselocks) {
0250         unsigned long flags;
0251         int result;
0252 
0253         spin_lock_irqsave(&budget->debilock, flags);
0254         result = ttpci_budget_debiread_nolock(budget, config, addr,
0255                               count, nobusyloop);
0256         spin_unlock_irqrestore(&budget->debilock, flags);
0257         return result;
0258     }
0259     return ttpci_budget_debiread_nolock(budget, config, addr,
0260                         count, nobusyloop);
0261 }
0262 
0263 static int ttpci_budget_debiwrite_nolock(struct budget *budget, u32 config,
0264         int addr, int count, u32 value, int nobusyloop)
0265 {
0266     struct saa7146_dev *saa = budget->dev;
0267     int result;
0268 
0269     result = saa7146_wait_for_debi_done(saa, nobusyloop);
0270     if (result < 0)
0271         return result;
0272 
0273     saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff));
0274     saa7146_write(saa, DEBI_CONFIG, config);
0275     saa7146_write(saa, DEBI_PAGE, 0);
0276     saa7146_write(saa, DEBI_AD, value);
0277     saa7146_write(saa, MC2, (2 << 16) | 2);
0278 
0279     result = saa7146_wait_for_debi_done(saa, nobusyloop);
0280     return result < 0 ? result : 0;
0281 }
0282 
0283 int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
0284                int count, u32 value, int uselocks, int nobusyloop)
0285 {
0286     if (count > 4 || count <= 0)
0287         return 0;
0288 
0289     if (uselocks) {
0290         unsigned long flags;
0291         int result;
0292 
0293         spin_lock_irqsave(&budget->debilock, flags);
0294         result = ttpci_budget_debiwrite_nolock(budget, config, addr,
0295                         count, value, nobusyloop);
0296         spin_unlock_irqrestore(&budget->debilock, flags);
0297         return result;
0298     }
0299     return ttpci_budget_debiwrite_nolock(budget, config, addr,
0300                          count, value, nobusyloop);
0301 }
0302 
0303 
0304 /****************************************************************************
0305  * DVB API SECTION
0306  ****************************************************************************/
0307 
0308 static int budget_start_feed(struct dvb_demux_feed *feed)
0309 {
0310     struct dvb_demux *demux = feed->demux;
0311     struct budget *budget = (struct budget *) demux->priv;
0312     int status = 0;
0313 
0314     dprintk(2, "budget: %p\n", budget);
0315 
0316     if (!demux->dmx.frontend)
0317         return -EINVAL;
0318 
0319     spin_lock(&budget->feedlock);
0320     feed->pusi_seen = false; /* have a clean section start */
0321     if (budget->feeding++ == 0)
0322         status = start_ts_capture(budget);
0323     spin_unlock(&budget->feedlock);
0324     return status;
0325 }
0326 
0327 static int budget_stop_feed(struct dvb_demux_feed *feed)
0328 {
0329     struct dvb_demux *demux = feed->demux;
0330     struct budget *budget = (struct budget *) demux->priv;
0331     int status = 0;
0332 
0333     dprintk(2, "budget: %p\n", budget);
0334 
0335     spin_lock(&budget->feedlock);
0336     if (--budget->feeding == 0)
0337         status = stop_ts_capture(budget);
0338     spin_unlock(&budget->feedlock);
0339     return status;
0340 }
0341 
0342 static int budget_register(struct budget *budget)
0343 {
0344     struct dvb_demux *dvbdemux = &budget->demux;
0345     int ret;
0346 
0347     dprintk(2, "budget: %p\n", budget);
0348 
0349     dvbdemux->priv = (void *) budget;
0350 
0351     dvbdemux->filternum = 256;
0352     dvbdemux->feednum = 256;
0353     dvbdemux->start_feed = budget_start_feed;
0354     dvbdemux->stop_feed = budget_stop_feed;
0355     dvbdemux->write_to_decoder = NULL;
0356 
0357     dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
0358                       DMX_MEMORY_BASED_FILTERING);
0359 
0360     dvb_dmx_init(&budget->demux);
0361 
0362     budget->dmxdev.filternum = 256;
0363     budget->dmxdev.demux = &dvbdemux->dmx;
0364     budget->dmxdev.capabilities = 0;
0365 
0366     dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter);
0367 
0368     budget->hw_frontend.source = DMX_FRONTEND_0;
0369 
0370     ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend);
0371 
0372     if (ret < 0)
0373         goto err_release_dmx;
0374 
0375     budget->mem_frontend.source = DMX_MEMORY_FE;
0376     ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
0377     if (ret < 0)
0378         goto err_release_dmx;
0379 
0380     ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
0381     if (ret < 0)
0382         goto err_release_dmx;
0383 
0384     dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);
0385 
0386     return 0;
0387 
0388 err_release_dmx:
0389     dvb_dmxdev_release(&budget->dmxdev);
0390     dvb_dmx_release(&budget->demux);
0391     return ret;
0392 }
0393 
0394 static void budget_unregister(struct budget *budget)
0395 {
0396     struct dvb_demux *dvbdemux = &budget->demux;
0397 
0398     dprintk(2, "budget: %p\n", budget);
0399 
0400     dvb_net_release(&budget->dvb_net);
0401 
0402     dvbdemux->dmx.close(&dvbdemux->dmx);
0403     dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend);
0404     dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend);
0405 
0406     dvb_dmxdev_release(&budget->dmxdev);
0407     dvb_dmx_release(&budget->demux);
0408 }
0409 
0410 int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
0411               struct saa7146_pci_extension_data *info,
0412               struct module *owner, short *adapter_nums)
0413 {
0414     int ret = 0;
0415     struct budget_info *bi = info->ext_priv;
0416     int max_bufsize;
0417     int height_mask;
0418 
0419     memset(budget, 0, sizeof(struct budget));
0420 
0421     dprintk(2, "dev: %p, budget: %p\n", dev, budget);
0422 
0423     budget->card = bi;
0424     budget->dev = (struct saa7146_dev *) dev;
0425 
0426     switch(budget->card->type) {
0427     case BUDGET_FS_ACTIVY:
0428         budget->buffer_width = TS_WIDTH_ACTIVY;
0429         max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY;
0430         height_mask = TS_HEIGHT_MASK_ACTIVY;
0431         break;
0432 
0433     case BUDGET_KNC1C:
0434     case BUDGET_KNC1CP:
0435     case BUDGET_CIN1200C:
0436     case BUDGET_KNC1C_MK3:
0437     case BUDGET_KNC1C_TDA10024:
0438     case BUDGET_KNC1CP_MK3:
0439     case BUDGET_CIN1200C_MK3:
0440         budget->buffer_width = TS_WIDTH_DVBC;
0441         max_bufsize = TS_MAX_BUFSIZE_K_DVBC;
0442         height_mask = TS_HEIGHT_MASK_DVBC;
0443         break;
0444 
0445     default:
0446         budget->buffer_width = TS_WIDTH;
0447         max_bufsize = TS_MAX_BUFSIZE_K;
0448         height_mask = TS_HEIGHT_MASK;
0449     }
0450 
0451     if (dma_buffer_size < TS_MIN_BUFSIZE_K)
0452         dma_buffer_size = TS_MIN_BUFSIZE_K;
0453     else if (dma_buffer_size > max_bufsize)
0454         dma_buffer_size = max_bufsize;
0455 
0456     budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width;
0457     if (budget->buffer_height > 0xfff) {
0458         budget->buffer_height /= 2;
0459         budget->buffer_height &= height_mask;
0460         budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width;
0461     } else {
0462         budget->buffer_height &= height_mask;
0463         budget->buffer_size = budget->buffer_height * budget->buffer_width;
0464     }
0465     budget->buffer_warning_threshold = budget->buffer_size * 80/100;
0466     budget->buffer_warnings = 0;
0467     budget->buffer_warning_time = jiffies;
0468 
0469     dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n",
0470         budget->dev->name,
0471         budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single",
0472         budget->buffer_width, budget->buffer_height);
0473     printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
0474 
0475     ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name,
0476                    owner, &budget->dev->pci->dev, adapter_nums);
0477     if (ret < 0)
0478         return ret;
0479 
0480     /* set dd1 stream a & b */
0481     saa7146_write(dev, DD1_STREAM_B, 0x00000000);
0482     saa7146_write(dev, MC2, (MASK_09 | MASK_25));
0483     saa7146_write(dev, MC2, (MASK_10 | MASK_26));
0484     saa7146_write(dev, DD1_INIT, 0x02000000);
0485     saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
0486 
0487     if (bi->type != BUDGET_FS_ACTIVY)
0488         budget->video_port = BUDGET_VIDEO_PORTB;
0489     else
0490         budget->video_port = BUDGET_VIDEO_PORTA;
0491     spin_lock_init(&budget->feedlock);
0492     spin_lock_init(&budget->debilock);
0493 
0494     /* the Siemens DVB needs this if you want to have the i2c chips
0495        get recognized before the main driver is loaded */
0496     if (bi->type != BUDGET_FS_ACTIVY)
0497         saa7146_write(dev, GPIO_CTRL, 0x500000);    /* GPIO 3 = 1 */
0498 
0499     strscpy(budget->i2c_adap.name, budget->card->name,
0500         sizeof(budget->i2c_adap.name));
0501 
0502     saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
0503     strscpy(budget->i2c_adap.name, budget->card->name,
0504         sizeof(budget->i2c_adap.name));
0505 
0506     if (i2c_add_adapter(&budget->i2c_adap) < 0) {
0507         ret = -ENOMEM;
0508         goto err_dvb_unregister;
0509     }
0510 
0511     ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac);
0512 
0513     budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt);
0514     if (NULL == budget->grabbing) {
0515         ret = -ENOMEM;
0516         goto err_del_i2c;
0517     }
0518 
0519     saa7146_write(dev, PCI_BT_V1, 0x001c0000);
0520     /* upload all */
0521     saa7146_write(dev, GPIO_CTRL, 0x000000);
0522 
0523     tasklet_setup(&budget->vpe_tasklet, vpeirq);
0524 
0525     /* frontend power on */
0526     if (bi->type != BUDGET_FS_ACTIVY)
0527         saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
0528 
0529     if ((ret = budget_register(budget)) == 0)
0530         return 0; /* Everything OK */
0531 
0532     /* An error occurred, cleanup resources */
0533     saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
0534 
0535 err_del_i2c:
0536     i2c_del_adapter(&budget->i2c_adap);
0537 
0538 err_dvb_unregister:
0539     dvb_unregister_adapter(&budget->dvb_adapter);
0540 
0541     return ret;
0542 }
0543 
0544 void ttpci_budget_init_hooks(struct budget *budget)
0545 {
0546     if (budget->dvb_frontend && !budget->read_fe_status) {
0547         budget->read_fe_status = budget->dvb_frontend->ops.read_status;
0548         budget->dvb_frontend->ops.read_status = budget_read_fe_status;
0549     }
0550 }
0551 
0552 int ttpci_budget_deinit(struct budget *budget)
0553 {
0554     struct saa7146_dev *dev = budget->dev;
0555 
0556     dprintk(2, "budget: %p\n", budget);
0557 
0558     budget_unregister(budget);
0559 
0560     tasklet_kill(&budget->vpe_tasklet);
0561 
0562     saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
0563 
0564     i2c_del_adapter(&budget->i2c_adap);
0565 
0566     dvb_unregister_adapter(&budget->dvb_adapter);
0567 
0568     return 0;
0569 }
0570 
0571 void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr)
0572 {
0573     struct budget *budget = (struct budget *) dev->ext_priv;
0574 
0575     dprintk(8, "dev: %p, budget: %p\n", dev, budget);
0576 
0577     if (*isr & MASK_10)
0578         tasklet_schedule(&budget->vpe_tasklet);
0579 }
0580 
0581 void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
0582 {
0583     struct budget *budget = (struct budget *) dev->ext_priv;
0584 
0585     spin_lock(&budget->feedlock);
0586     budget->video_port = video_port;
0587     if (budget->feeding) {
0588         stop_ts_capture(budget);
0589         start_ts_capture(budget);
0590     }
0591     spin_unlock(&budget->feedlock);
0592 }
0593 
0594 EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
0595 EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
0596 EXPORT_SYMBOL_GPL(ttpci_budget_init);
0597 EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks);
0598 EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
0599 EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
0600 EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
0601 EXPORT_SYMBOL_GPL(budget_debug);
0602 
0603 MODULE_LICENSE("GPL");