162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * large parts based on the bttv driver 862306a36Sopenharmony_ci * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) 962306a36Sopenharmony_ci * & Marcus Metzler (mocm@metzlerbros.de) 1062306a36Sopenharmony_ci * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/pci.h> 1662306a36Sopenharmony_ci#include <linux/pgtable.h> 1762306a36Sopenharmony_ci#include <asm/io.h> 1862306a36Sopenharmony_ci#include <linux/ioport.h> 1962306a36Sopenharmony_ci#include <asm/page.h> 2062306a36Sopenharmony_ci#include <linux/types.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/kmod.h> 2362306a36Sopenharmony_ci#include <linux/vmalloc.h> 2462306a36Sopenharmony_ci#include <linux/init.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <media/dmxdev.h> 2762306a36Sopenharmony_ci#include <media/dvbdev.h> 2862306a36Sopenharmony_ci#include "bt878.h" 2962306a36Sopenharmony_ci#include "dst_priv.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/**************************************/ 3362306a36Sopenharmony_ci/* Miscellaneous utility definitions */ 3462306a36Sopenharmony_ci/**************************************/ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic unsigned int bt878_verbose = 1; 3762306a36Sopenharmony_cistatic unsigned int bt878_debug; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cimodule_param_named(verbose, bt878_verbose, int, 0444); 4062306a36Sopenharmony_ciMODULE_PARM_DESC(verbose, 4162306a36Sopenharmony_ci "verbose startup messages, default is 1 (yes)"); 4262306a36Sopenharmony_cimodule_param_named(debug, bt878_debug, int, 0644); 4362306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off)."); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciint bt878_num; 4662306a36Sopenharmony_cistruct bt878 bt878[BT878_MAX]; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciEXPORT_SYMBOL(bt878_num); 4962306a36Sopenharmony_ciEXPORT_SYMBOL(bt878); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr))) 5262306a36Sopenharmony_ci#define btread(adr) bmtread(bt->bt878_mem+(adr)) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define btand(dat,adr) btwrite((dat) & btread(adr), adr) 5562306a36Sopenharmony_ci#define btor(dat,adr) btwrite((dat) | btread(adr), adr) 5662306a36Sopenharmony_ci#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#if defined(dprintk) 5962306a36Sopenharmony_ci#undef dprintk 6062306a36Sopenharmony_ci#endif 6162306a36Sopenharmony_ci#define dprintk(fmt, arg...) \ 6262306a36Sopenharmony_ci do { \ 6362306a36Sopenharmony_ci if (bt878_debug) \ 6462306a36Sopenharmony_ci printk(KERN_DEBUG fmt, ##arg); \ 6562306a36Sopenharmony_ci } while (0) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void bt878_mem_free(struct bt878 *bt) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci if (bt->buf_cpu) { 7062306a36Sopenharmony_ci dma_free_coherent(&bt->dev->dev, bt->buf_size, bt->buf_cpu, 7162306a36Sopenharmony_ci bt->buf_dma); 7262306a36Sopenharmony_ci bt->buf_cpu = NULL; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (bt->risc_cpu) { 7662306a36Sopenharmony_ci dma_free_coherent(&bt->dev->dev, bt->risc_size, bt->risc_cpu, 7762306a36Sopenharmony_ci bt->risc_dma); 7862306a36Sopenharmony_ci bt->risc_cpu = NULL; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int bt878_mem_alloc(struct bt878 *bt) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci if (!bt->buf_cpu) { 8562306a36Sopenharmony_ci bt->buf_size = 128 * 1024; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci bt->buf_cpu = dma_alloc_coherent(&bt->dev->dev, bt->buf_size, 8862306a36Sopenharmony_ci &bt->buf_dma, GFP_KERNEL); 8962306a36Sopenharmony_ci if (!bt->buf_cpu) 9062306a36Sopenharmony_ci return -ENOMEM; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (!bt->risc_cpu) { 9462306a36Sopenharmony_ci bt->risc_size = PAGE_SIZE; 9562306a36Sopenharmony_ci bt->risc_cpu = dma_alloc_coherent(&bt->dev->dev, bt->risc_size, 9662306a36Sopenharmony_ci &bt->risc_dma, GFP_KERNEL); 9762306a36Sopenharmony_ci if (!bt->risc_cpu) { 9862306a36Sopenharmony_ci bt878_mem_free(bt); 9962306a36Sopenharmony_ci return -ENOMEM; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* RISC instructions */ 10762306a36Sopenharmony_ci#define RISC_WRITE (0x01 << 28) 10862306a36Sopenharmony_ci#define RISC_JUMP (0x07 << 28) 10962306a36Sopenharmony_ci#define RISC_SYNC (0x08 << 28) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* RISC bits */ 11262306a36Sopenharmony_ci#define RISC_WR_SOL (1 << 27) 11362306a36Sopenharmony_ci#define RISC_WR_EOL (1 << 26) 11462306a36Sopenharmony_ci#define RISC_IRQ (1 << 24) 11562306a36Sopenharmony_ci#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16)) 11662306a36Sopenharmony_ci#define RISC_SYNC_RESYNC (1 << 15) 11762306a36Sopenharmony_ci#define RISC_SYNC_FM1 0x06 11862306a36Sopenharmony_ci#define RISC_SYNC_VRO 0x0C 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define RISC_FLUSH() bt->risc_pos = 0 12162306a36Sopenharmony_ci#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int bt878_make_risc(struct bt878 *bt) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci bt->block_bytes = bt->buf_size >> 4; 12662306a36Sopenharmony_ci bt->block_count = 1 << 4; 12762306a36Sopenharmony_ci bt->line_bytes = bt->block_bytes; 12862306a36Sopenharmony_ci bt->line_count = bt->block_count; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci while (bt->line_bytes > 4095) { 13162306a36Sopenharmony_ci bt->line_bytes >>= 1; 13262306a36Sopenharmony_ci bt->line_count <<= 1; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (bt->line_count > 255) { 13662306a36Sopenharmony_ci printk(KERN_ERR "bt878: buffer size error!\n"); 13762306a36Sopenharmony_ci return -EINVAL; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci u32 buf_pos = 0; 14662306a36Sopenharmony_ci u32 line; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci RISC_FLUSH(); 14962306a36Sopenharmony_ci RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin); 15062306a36Sopenharmony_ci RISC_INSTR(0); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci dprintk("bt878: risc len lines %u, bytes per line %u\n", 15362306a36Sopenharmony_ci bt->line_count, bt->line_bytes); 15462306a36Sopenharmony_ci for (line = 0; line < bt->line_count; line++) { 15562306a36Sopenharmony_ci // At the beginning of every block we issue an IRQ with previous (finished) block number set 15662306a36Sopenharmony_ci if (!(buf_pos % bt->block_bytes)) 15762306a36Sopenharmony_ci RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | 15862306a36Sopenharmony_ci RISC_IRQ | 15962306a36Sopenharmony_ci RISC_STATUS(((buf_pos / 16062306a36Sopenharmony_ci bt->block_bytes) + 16162306a36Sopenharmony_ci (bt->block_count - 16262306a36Sopenharmony_ci 1)) % 16362306a36Sopenharmony_ci bt->block_count) | bt-> 16462306a36Sopenharmony_ci line_bytes); 16562306a36Sopenharmony_ci else 16662306a36Sopenharmony_ci RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | 16762306a36Sopenharmony_ci bt->line_bytes); 16862306a36Sopenharmony_ci RISC_INSTR(bt->buf_dma + buf_pos); 16962306a36Sopenharmony_ci buf_pos += bt->line_bytes; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO); 17362306a36Sopenharmony_ci RISC_INSTR(0); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci RISC_INSTR(RISC_JUMP); 17662306a36Sopenharmony_ci RISC_INSTR(bt->risc_dma); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/*****************************/ 18262306a36Sopenharmony_ci/* Start/Stop grabbing funcs */ 18362306a36Sopenharmony_ci/*****************************/ 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_civoid bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, 18662306a36Sopenharmony_ci u32 irq_err_ignore) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci u32 int_mask; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg); 19162306a36Sopenharmony_ci /* complete the writing of the risc dma program now we have 19262306a36Sopenharmony_ci * the card specifics 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci bt878_risc_program(bt, op_sync_orin); 19562306a36Sopenharmony_ci controlreg &= ~0x1f; 19662306a36Sopenharmony_ci controlreg |= 0x1b; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci btwrite(bt->risc_dma, BT878_ARISC_START); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* original int mask had : 20162306a36Sopenharmony_ci * 6 2 8 4 0 20262306a36Sopenharmony_ci * 1111 1111 1000 0000 0000 20362306a36Sopenharmony_ci * SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI 20462306a36Sopenharmony_ci * Hacked for DST to: 20562306a36Sopenharmony_ci * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | 20862306a36Sopenharmony_ci BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | 20962306a36Sopenharmony_ci BT878_AFBUS | BT878_ARISCI; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* ignore pesky bits */ 21362306a36Sopenharmony_ci int_mask &= ~irq_err_ignore; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci btwrite(int_mask, BT878_AINT_MASK); 21662306a36Sopenharmony_ci btwrite(controlreg, BT878_AGPIO_DMA_CTL); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_civoid bt878_stop(struct bt878 *bt) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci u32 stat; 22262306a36Sopenharmony_ci int i = 0; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci dprintk("bt878 debug: bt878_stop\n"); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci btwrite(0, BT878_AINT_MASK); 22762306a36Sopenharmony_ci btand(~0x13, BT878_AGPIO_DMA_CTL); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci do { 23062306a36Sopenharmony_ci stat = btread(BT878_AINT_STAT); 23162306a36Sopenharmony_ci if (!(stat & BT878_ARISC_EN)) 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci i++; 23462306a36Sopenharmony_ci } while (i < 500); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n", 23762306a36Sopenharmony_ci bt->nr, i, stat); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ciEXPORT_SYMBOL(bt878_start); 24162306a36Sopenharmony_ciEXPORT_SYMBOL(bt878_stop); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/*****************************/ 24462306a36Sopenharmony_ci/* Interrupt service routine */ 24562306a36Sopenharmony_ci/*****************************/ 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic irqreturn_t bt878_irq(int irq, void *dev_id) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci u32 stat, astat, mask; 25062306a36Sopenharmony_ci int count; 25162306a36Sopenharmony_ci struct bt878 *bt; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci bt = (struct bt878 *) dev_id; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci count = 0; 25662306a36Sopenharmony_ci while (1) { 25762306a36Sopenharmony_ci stat = btread(BT878_AINT_STAT); 25862306a36Sopenharmony_ci mask = btread(BT878_AINT_MASK); 25962306a36Sopenharmony_ci if (!(astat = (stat & mask))) 26062306a36Sopenharmony_ci return IRQ_NONE; /* this interrupt is not for me */ 26162306a36Sopenharmony_ci/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */ 26262306a36Sopenharmony_ci btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */ 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (astat & (BT878_ASCERR | BT878_AOCERR)) { 26662306a36Sopenharmony_ci if (bt878_verbose) { 26762306a36Sopenharmony_ci printk(KERN_INFO 26862306a36Sopenharmony_ci "bt878(%d): irq%s%s risc_pc=%08x\n", 26962306a36Sopenharmony_ci bt->nr, 27062306a36Sopenharmony_ci (astat & BT878_ASCERR) ? " SCERR" : 27162306a36Sopenharmony_ci "", 27262306a36Sopenharmony_ci (astat & BT878_AOCERR) ? " OCERR" : 27362306a36Sopenharmony_ci "", btread(BT878_ARISC_PC)); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) { 27762306a36Sopenharmony_ci if (bt878_verbose) { 27862306a36Sopenharmony_ci printk(KERN_INFO 27962306a36Sopenharmony_ci "bt878(%d): irq%s%s%s risc_pc=%08x\n", 28062306a36Sopenharmony_ci bt->nr, 28162306a36Sopenharmony_ci (astat & BT878_APABORT) ? " PABORT" : 28262306a36Sopenharmony_ci "", 28362306a36Sopenharmony_ci (astat & BT878_ARIPERR) ? " RIPERR" : 28462306a36Sopenharmony_ci "", 28562306a36Sopenharmony_ci (astat & BT878_APPERR) ? " PPERR" : 28662306a36Sopenharmony_ci "", btread(BT878_ARISC_PC)); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) { 29062306a36Sopenharmony_ci if (bt878_verbose) { 29162306a36Sopenharmony_ci printk(KERN_INFO 29262306a36Sopenharmony_ci "bt878(%d): irq%s%s%s risc_pc=%08x\n", 29362306a36Sopenharmony_ci bt->nr, 29462306a36Sopenharmony_ci (astat & BT878_AFDSR) ? " FDSR" : "", 29562306a36Sopenharmony_ci (astat & BT878_AFTRGT) ? " FTRGT" : 29662306a36Sopenharmony_ci "", 29762306a36Sopenharmony_ci (astat & BT878_AFBUS) ? " FBUS" : "", 29862306a36Sopenharmony_ci btread(BT878_ARISC_PC)); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci if (astat & BT878_ARISCI) { 30262306a36Sopenharmony_ci bt->finished_block = (stat & BT878_ARISCS) >> 28; 30362306a36Sopenharmony_ci if (bt->tasklet.callback) 30462306a36Sopenharmony_ci tasklet_schedule(&bt->tasklet); 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci count++; 30862306a36Sopenharmony_ci if (count > 20) { 30962306a36Sopenharmony_ci btwrite(0, BT878_AINT_MASK); 31062306a36Sopenharmony_ci printk(KERN_ERR 31162306a36Sopenharmony_ci "bt878(%d): IRQ lockup, cleared int mask\n", 31262306a36Sopenharmony_ci bt->nr); 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci return IRQ_HANDLED; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ciint 32062306a36Sopenharmony_cibt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci int retval; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci retval = 0; 32562306a36Sopenharmony_ci if (mutex_lock_interruptible(&bt->gpio_lock)) 32662306a36Sopenharmony_ci return -ERESTARTSYS; 32762306a36Sopenharmony_ci /* special gpio signal */ 32862306a36Sopenharmony_ci switch (cmd) { 32962306a36Sopenharmony_ci case DST_IG_ENABLE: 33062306a36Sopenharmony_ci // dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable); 33162306a36Sopenharmony_ci retval = bttv_gpio_enable(bt->bttv_nr, 33262306a36Sopenharmony_ci mp->enb.mask, 33362306a36Sopenharmony_ci mp->enb.enable); 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci case DST_IG_WRITE: 33662306a36Sopenharmony_ci // dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals); 33762306a36Sopenharmony_ci retval = bttv_write_gpio(bt->bttv_nr, 33862306a36Sopenharmony_ci mp->outp.mask, 33962306a36Sopenharmony_ci mp->outp.highvals); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci case DST_IG_READ: 34362306a36Sopenharmony_ci /* read */ 34462306a36Sopenharmony_ci retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value); 34562306a36Sopenharmony_ci // dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value); 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci case DST_IG_TS: 34862306a36Sopenharmony_ci /* Set packet size */ 34962306a36Sopenharmony_ci bt->TS_Size = mp->psize; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci default: 35362306a36Sopenharmony_ci retval = -EINVAL; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci mutex_unlock(&bt->gpio_lock); 35762306a36Sopenharmony_ci return retval; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ciEXPORT_SYMBOL(bt878_device_control); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci#define BROOKTREE_878_DEVICE(vend, dev, name) \ 36362306a36Sopenharmony_ci { \ 36462306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_BROOKTREE, \ 36562306a36Sopenharmony_ci .device = PCI_DEVICE_ID_BROOKTREE_878, \ 36662306a36Sopenharmony_ci .subvendor = (vend), .subdevice = (dev), \ 36762306a36Sopenharmony_ci .driver_data = (unsigned long) name \ 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic const struct pci_device_id bt878_pci_tbl[] = { 37162306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), 37262306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), 37362306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), 37462306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), 37562306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), 37662306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x270f, 0xfc00, 37762306a36Sopenharmony_ci "ChainTech digitop DST-1000 DVB-S"), 37862306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), 37962306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), 38062306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), 38162306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), 38262306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), 38362306a36Sopenharmony_ci BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), 38462306a36Sopenharmony_ci { } 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, bt878_pci_tbl); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic const char * card_name(const struct pci_device_id *id) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci return id->driver_data ? (const char *)id->driver_data : "Unknown"; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/***********************/ 39562306a36Sopenharmony_ci/* PCI device handling */ 39662306a36Sopenharmony_ci/***********************/ 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci int result = 0; 40162306a36Sopenharmony_ci unsigned char lat; 40262306a36Sopenharmony_ci struct bt878 *bt; 40362306a36Sopenharmony_ci unsigned int cardid; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", 40662306a36Sopenharmony_ci bt878_num); 40762306a36Sopenharmony_ci if (bt878_num >= BT878_MAX) { 40862306a36Sopenharmony_ci printk(KERN_ERR "bt878: Too many devices inserted\n"); 40962306a36Sopenharmony_ci return -ENOMEM; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci if (pci_enable_device(dev)) 41262306a36Sopenharmony_ci return -EIO; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci cardid = dev->subsystem_device << 16; 41562306a36Sopenharmony_ci cardid |= dev->subsystem_vendor; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", 41862306a36Sopenharmony_ci __func__, cardid, card_name(pci_id)); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci bt = &bt878[bt878_num]; 42162306a36Sopenharmony_ci bt->dev = dev; 42262306a36Sopenharmony_ci bt->nr = bt878_num; 42362306a36Sopenharmony_ci bt->shutdown = 0; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci bt->id = dev->device; 42662306a36Sopenharmony_ci bt->irq = dev->irq; 42762306a36Sopenharmony_ci bt->bt878_adr = pci_resource_start(dev, 0); 42862306a36Sopenharmony_ci if (!request_mem_region(pci_resource_start(dev, 0), 42962306a36Sopenharmony_ci pci_resource_len(dev, 0), "bt878")) { 43062306a36Sopenharmony_ci result = -EBUSY; 43162306a36Sopenharmony_ci goto fail0; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci bt->revision = dev->revision; 43562306a36Sopenharmony_ci pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ", 43962306a36Sopenharmony_ci bt878_num, bt->id, bt->revision, dev->bus->number, 44062306a36Sopenharmony_ci PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); 44162306a36Sopenharmony_ci printk("irq: %d, latency: %d, memory: 0x%lx\n", 44262306a36Sopenharmony_ci bt->irq, lat, bt->bt878_adr); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci#ifdef __sparc__ 44562306a36Sopenharmony_ci bt->bt878_mem = (unsigned char *) bt->bt878_adr; 44662306a36Sopenharmony_ci#else 44762306a36Sopenharmony_ci bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000); 44862306a36Sopenharmony_ci#endif 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* clear interrupt mask */ 45162306a36Sopenharmony_ci btwrite(0, BT848_INT_MASK); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci result = request_irq(bt->irq, bt878_irq, 45462306a36Sopenharmony_ci IRQF_SHARED, "bt878", (void *) bt); 45562306a36Sopenharmony_ci if (result == -EINVAL) { 45662306a36Sopenharmony_ci printk(KERN_ERR "bt878(%d): Bad irq number or handler\n", 45762306a36Sopenharmony_ci bt878_num); 45862306a36Sopenharmony_ci goto fail1; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci if (result == -EBUSY) { 46162306a36Sopenharmony_ci printk(KERN_ERR 46262306a36Sopenharmony_ci "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n", 46362306a36Sopenharmony_ci bt878_num, bt->irq); 46462306a36Sopenharmony_ci goto fail1; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci if (result < 0) 46762306a36Sopenharmony_ci goto fail1; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci pci_set_master(dev); 47062306a36Sopenharmony_ci pci_set_drvdata(dev, bt); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if ((result = bt878_mem_alloc(bt))) { 47362306a36Sopenharmony_ci printk(KERN_ERR "bt878: failed to allocate memory!\n"); 47462306a36Sopenharmony_ci goto fail2; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci bt878_make_risc(bt); 47862306a36Sopenharmony_ci btwrite(0, BT878_AINT_MASK); 47962306a36Sopenharmony_ci bt878_num++; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (!bt->tasklet.func) 48262306a36Sopenharmony_ci tasklet_disable(&bt->tasklet); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci fail2: 48762306a36Sopenharmony_ci free_irq(bt->irq, bt); 48862306a36Sopenharmony_ci fail1: 48962306a36Sopenharmony_ci release_mem_region(pci_resource_start(bt->dev, 0), 49062306a36Sopenharmony_ci pci_resource_len(bt->dev, 0)); 49162306a36Sopenharmony_ci fail0: 49262306a36Sopenharmony_ci pci_disable_device(dev); 49362306a36Sopenharmony_ci return result; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic void bt878_remove(struct pci_dev *pci_dev) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci u8 command; 49962306a36Sopenharmony_ci struct bt878 *bt = pci_get_drvdata(pci_dev); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (bt878_verbose) 50262306a36Sopenharmony_ci printk(KERN_INFO "bt878(%d): unloading\n", bt->nr); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* turn off all capturing, DMA and IRQs */ 50562306a36Sopenharmony_ci btand(~0x13, BT878_AGPIO_DMA_CTL); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* first disable interrupts before unmapping the memory! */ 50862306a36Sopenharmony_ci btwrite(0, BT878_AINT_MASK); 50962306a36Sopenharmony_ci btwrite(~0U, BT878_AINT_STAT); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* disable PCI bus-mastering */ 51262306a36Sopenharmony_ci pci_read_config_byte(bt->dev, PCI_COMMAND, &command); 51362306a36Sopenharmony_ci /* Should this be &=~ ?? */ 51462306a36Sopenharmony_ci command &= ~PCI_COMMAND_MASTER; 51562306a36Sopenharmony_ci pci_write_config_byte(bt->dev, PCI_COMMAND, command); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci free_irq(bt->irq, bt); 51862306a36Sopenharmony_ci printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem); 51962306a36Sopenharmony_ci if (bt->bt878_mem) 52062306a36Sopenharmony_ci iounmap(bt->bt878_mem); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci release_mem_region(pci_resource_start(bt->dev, 0), 52362306a36Sopenharmony_ci pci_resource_len(bt->dev, 0)); 52462306a36Sopenharmony_ci /* wake up any waiting processes 52562306a36Sopenharmony_ci because shutdown flag is set, no new processes (in this queue) 52662306a36Sopenharmony_ci are expected 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_ci bt->shutdown = 1; 52962306a36Sopenharmony_ci bt878_mem_free(bt); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci pci_disable_device(pci_dev); 53262306a36Sopenharmony_ci return; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic struct pci_driver bt878_pci_driver = { 53662306a36Sopenharmony_ci .name = "bt878", 53762306a36Sopenharmony_ci .id_table = bt878_pci_tbl, 53862306a36Sopenharmony_ci .probe = bt878_probe, 53962306a36Sopenharmony_ci .remove = bt878_remove, 54062306a36Sopenharmony_ci}; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/*******************************/ 54362306a36Sopenharmony_ci/* Module management functions */ 54462306a36Sopenharmony_ci/*******************************/ 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic int __init bt878_init_module(void) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci bt878_num = 0; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n", 55162306a36Sopenharmony_ci (BT878_VERSION_CODE >> 16) & 0xff, 55262306a36Sopenharmony_ci (BT878_VERSION_CODE >> 8) & 0xff, 55362306a36Sopenharmony_ci BT878_VERSION_CODE & 0xff); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return pci_register_driver(&bt878_pci_driver); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic void __exit bt878_cleanup_module(void) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci pci_unregister_driver(&bt878_pci_driver); 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cimodule_init(bt878_init_module); 56462306a36Sopenharmony_cimodule_exit(bt878_cleanup_module); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 567