Mauro Carvalho Chehab wrote: > Hi Oliver, > > Oliver Endriss wrote: >> Mauro, >> > As usual, after receiving your fixes for the above, I'll review the driver > manually. > OK, I'm enclosing here the diff file to allow comments. I found just a few issues, please see bellow. Yet, I decided to keep the entire diff, as more people may want to review and comment. Cheers, Mauro. --- PS.: This is the diff file for the -git version, without any backports. After having it merged, Douglas will pull from the ngene mercurial tree, to retrieve also the backports. > diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig > index cf8f65f..161ccfd 100644 > --- a/drivers/media/dvb/Kconfig > +++ b/drivers/media/dvb/Kconfig > @@ -76,6 +76,10 @@ comment "Supported Mantis Adapters" > depends on DVB_CORE && PCI && I2C > source "drivers/media/dvb/mantis/Kconfig" > > +comment "Supported nGene Adapters" > + depends on DVB_CORE && PCI && I2C > + source "drivers/media/dvb/ngene/Kconfig" > + > comment "Supported DVB Frontends" > depends on DVB_CORE > source "drivers/media/dvb/frontends/Kconfig" > diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile > index c12922c..a1a0875 100644 > --- a/drivers/media/dvb/Makefile > +++ b/drivers/media/dvb/Makefile > @@ -14,6 +14,7 @@ obj-y := dvb-core/ \ > siano/ \ > dm1105/ \ > pt1/ \ > - mantis/ > + mantis/ \ > + ngene/ > > obj-$(CONFIG_DVB_FIREDTV) += firewire/ > diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c > index 584bbd1..a5712cd 100644 > --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c > +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c > @@ -89,6 +89,7 @@ void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) > rbuf->pread = rbuf->pwrite; > rbuf->error = 0; > } > +EXPORT_SYMBOL(dvb_ringbuffer_flush); > > void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf) > { > diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig > new file mode 100644 > index 0000000..3ec8e6f > --- /dev/null > +++ b/drivers/media/dvb/ngene/Kconfig > @@ -0,0 +1,9 @@ > +config DVB_NGENE > + tristate "Micronas nGene support" > + depends on DVB_CORE && PCI && I2C > + select DVB_LNBP21 if !DVB_FE_CUSTOMISE > + select DVB_STV6110x if !DVB_FE_CUSTOMISE > + select DVB_STV090x if !DVB_FE_CUSTOMISE > + ---help--- > + Support for Micronas PCI express cards with nGene bridge. > + > diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile > new file mode 100644 > index 0000000..40435ca > --- /dev/null > +++ b/drivers/media/dvb/ngene/Makefile > @@ -0,0 +1,11 @@ > +# > +# Makefile for the nGene device driver > +# > + > +ngene-objs := ngene-core.o > + > +obj-$(CONFIG_DVB_NGENE) += ngene.o > + > +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ > +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ > + > diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c > new file mode 100644 > index 0000000..1bb9bc7 > --- /dev/null > +++ b/drivers/media/dvb/ngene/ngene-core.c > @@ -0,0 +1,2026 @@ > +/* > + * ngene.c: nGene PCIe bridge driver > + * > + * Copyright (C) 2005-2007 Micronas > + * > + * Copyright (C) 2008-2009 Ralph Metzler <rjkm@xxxxxxxxxxxxxx> > + * Modifications for new nGene firmware, > + * support for EEPROM-copying, > + * support for new dual DVB-S2 card prototype > + * > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * version 2 only, as published by the Free Software Foundation. > + * > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > + * 02110-1301, USA > + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html > + */ > + > +#include <linux/module.h> > +#include <linux/init.h> > +#include <linux/delay.h> > +#include <linux/slab.h> > +#include <linux/poll.h> > +#include <asm/io.h> > +#include <asm/div64.h> > +#include <linux/pci.h> > +#include <linux/pci_ids.h> > +#include <linux/smp_lock.h> > +#include <linux/timer.h> > +#include <linux/version.h> > +#include <linux/byteorder/generic.h> > +#include <linux/firmware.h> > + > +#include "ngene.h" > + > +#include "stv6110x.h" > +#include "stv090x.h" > +#include "lnbh24.h" > + > +static int one_adapter = 1; > +module_param(one_adapter, int, 0444); > +MODULE_PARM_DESC(one_adapter, "Use only one adapter."); > + > + > +static int debug; > +module_param(debug, int, 0444); > +MODULE_PARM_DESC(debug, "Print debugging information."); > + > +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); > + > +#define COMMAND_TIMEOUT_WORKAROUND Why do you need the above define? There are several places at the code where this is used. Maybe it should also be a module parameter, like the change done with one_adapter. > + > +#define dprintk if (debug) printk > + > +#define DEVICE_NAME "ngene" > + > +#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) > +#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) > +#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) > +#define ngreadl(adr) readl(dev->iomem + (adr)) > +#define ngreadb(adr) readb(dev->iomem + (adr)) > +#define ngcpyto(adr, src, count) memcpy_toio((char *) \ > + (dev->iomem + (adr)), (src), (count)) > +#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ > + (dev->iomem + (adr)), (count)) > + > +/****************************************************************************/ > +/* nGene interrupt handler **************************************************/ > +/****************************************************************************/ > + > +static void event_tasklet(unsigned long data) > +{ > + struct ngene *dev = (struct ngene *)data; > + > + while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { > + struct EVENT_BUFFER Event = > + dev->EventQueue[dev->EventQueueReadIndex]; > + dev->EventQueueReadIndex = > + (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1); > + > + if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify)) > + dev->TxEventNotify(dev, Event.TimeStamp); > + if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify)) > + dev->RxEventNotify(dev, Event.TimeStamp, > + Event.RXCharacter); > + } > +} > + > +static void demux_tasklet(unsigned long data) > +{ > + struct ngene_channel *chan = (struct ngene_channel *)data; > + struct SBufferHeader *Cur = chan->nextBuffer; > + > + spin_lock_irq(&chan->state_lock); > + > + while (Cur->ngeneBuffer.SR.Flags & 0x80) { > + if (chan->mode & NGENE_IO_TSOUT) { > + u32 Flags = chan->DataFormatFlags; > + if (Cur->ngeneBuffer.SR.Flags & 0x20) > + Flags |= BEF_OVERFLOW; > + if (chan->pBufferExchange) { > + if (!chan->pBufferExchange(chan, > + Cur->Buffer1, > + chan->Capture1Length, > + Cur->ngeneBuffer.SR. > + Clock, Flags)) { > + /* > + We didn't get data > + Clear in service flag to make sure we > + get called on next interrupt again. > + leave fill/empty (0x80) flag alone > + to avoid hardware running out of > + buffers during startup, we hold only > + in run state ( the source may be late > + delivering data ) > + */ > + > + if (chan->HWState == HWSTATE_RUN) { > + Cur->ngeneBuffer.SR.Flags &= > + ~0x40; > + break; > + /* Stop proccessing stream */ > + } > + } else { > + /* We got a valid buffer, > + so switch to run state */ > + chan->HWState = HWSTATE_RUN; > + } > + } else { > + printk(KERN_ERR DEVICE_NAME ": OOPS\n"); > + if (chan->HWState == HWSTATE_RUN) { > + Cur->ngeneBuffer.SR.Flags &= ~0x40; > + break; /* Stop proccessing stream */ > + } > + } > + if (chan->AudioDTOUpdated) { > + printk(KERN_INFO DEVICE_NAME > + ": Update AudioDTO = %d\n", > + chan->AudioDTOValue); > + Cur->ngeneBuffer.SR.DTOUpdate = > + chan->AudioDTOValue; > + chan->AudioDTOUpdated = 0; > + } > + } else { > + if (chan->HWState == HWSTATE_RUN) { > + u32 Flags = 0; > + if (Cur->ngeneBuffer.SR.Flags & 0x01) > + Flags |= BEF_EVEN_FIELD; > + if (Cur->ngeneBuffer.SR.Flags & 0x20) > + Flags |= BEF_OVERFLOW; > + if (chan->pBufferExchange) > + chan->pBufferExchange(chan, > + Cur->Buffer1, > + chan-> > + Capture1Length, > + Cur->ngeneBuffer. > + SR.Clock, Flags); > + if (chan->pBufferExchange2) > + chan->pBufferExchange2(chan, > + Cur->Buffer2, > + chan-> > + Capture2Length, > + Cur->ngeneBuffer. > + SR.Clock, Flags); > + } else if (chan->HWState != HWSTATE_STOP) > + chan->HWState = HWSTATE_RUN; > + } > + Cur->ngeneBuffer.SR.Flags = 0x00; > + Cur = Cur->Next; > + } > + chan->nextBuffer = Cur; > + > + spin_unlock_irq(&chan->state_lock); > +} > + > +static irqreturn_t irq_handler(int irq, void *dev_id) > +{ > + struct ngene *dev = (struct ngene *)dev_id; > + u32 icounts = 0; > + irqreturn_t rc = IRQ_NONE; > + u32 i = MAX_STREAM; > + u8 *tmpCmdDoneByte; > + > + if (dev->BootFirmware) { > + icounts = ngreadl(NGENE_INT_COUNTS); > + if (icounts != dev->icounts) { > + ngwritel(0, FORCE_NMI); > + dev->cmd_done = 1; > + wake_up(&dev->cmd_wq); > + dev->icounts = icounts; > + rc = IRQ_HANDLED; > + } > + return rc; > + } > + > + ngwritel(0, FORCE_NMI); > + > + spin_lock(&dev->cmd_lock); > + tmpCmdDoneByte = dev->CmdDoneByte; > + if (tmpCmdDoneByte && > + (*tmpCmdDoneByte || > + (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) { > + dev->CmdDoneByte = NULL; > + dev->cmd_done = 1; > + wake_up(&dev->cmd_wq); > + rc = IRQ_HANDLED; > + } > + spin_unlock(&dev->cmd_lock); > + > + if (dev->EventBuffer->EventStatus & 0x80) { > + u8 nextWriteIndex = > + (dev->EventQueueWriteIndex + 1) & > + (EVENT_QUEUE_SIZE - 1); > + if (nextWriteIndex != dev->EventQueueReadIndex) { > + dev->EventQueue[dev->EventQueueWriteIndex] = > + *(dev->EventBuffer); > + dev->EventQueueWriteIndex = nextWriteIndex; > + } else { > + printk(KERN_ERR DEVICE_NAME ": event overflow\n"); > + dev->EventQueueOverflowCount += 1; > + dev->EventQueueOverflowFlag = 1; > + } > + dev->EventBuffer->EventStatus &= ~0x80; > + tasklet_schedule(&dev->event_tasklet); > + rc = IRQ_HANDLED; > + } > + > + while (i > 0) { > + i--; > + spin_lock(&dev->channel[i].state_lock); > + /* if (dev->channel[i].State>=KSSTATE_RUN) { */ > + if (dev->channel[i].nextBuffer) { > + if ((dev->channel[i].nextBuffer-> > + ngeneBuffer.SR.Flags & 0xC0) == 0x80) { > + dev->channel[i].nextBuffer-> > + ngeneBuffer.SR.Flags |= 0x40; > + tasklet_schedule( > + &dev->channel[i].demux_tasklet); > + rc = IRQ_HANDLED; > + } > + } > + spin_unlock(&dev->channel[i].state_lock); > + } > + > + /* Request might have been processed by a previous call. */ > + return IRQ_HANDLED; > +} > + > +/****************************************************************************/ > +/* nGene command interface **************************************************/ > +/****************************************************************************/ > + > +static void dump_command_io(struct ngene *dev) > +{ > + u8 buf[8], *b; > + > + ngcpyfrom(buf, HOST_TO_NGENE, 8); > + printk(KERN_ERR "host_to_ngene (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n", > + HOST_TO_NGENE, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); > + > + ngcpyfrom(buf, NGENE_TO_HOST, 8); > + printk(KERN_ERR "ngene_to_host (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n", > + NGENE_TO_HOST, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); > + > + b = dev->hosttongene; > + printk(KERN_ERR "dev->hosttongene (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n", > + b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); > + > + b = dev->ngenetohost; > + printk(KERN_ERR "dev->ngenetohost (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n", > + b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); > +} > + > +static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) > +{ > + int ret; > + u8 *tmpCmdDoneByte; > + > + dev->cmd_done = 0; > + > + if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) { > + dev->BootFirmware = 1; > + dev->icounts = ngreadl(NGENE_INT_COUNTS); > + ngwritel(0, NGENE_COMMAND); > + ngwritel(0, NGENE_COMMAND_HI); > + ngwritel(0, NGENE_STATUS); > + ngwritel(0, NGENE_STATUS_HI); > + ngwritel(0, NGENE_EVENT); > + ngwritel(0, NGENE_EVENT_HI); > + } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) { > + u64 fwio = dev->PAFWInterfaceBuffer; > + > + ngwritel(fwio & 0xffffffff, NGENE_COMMAND); > + ngwritel(fwio >> 32, NGENE_COMMAND_HI); > + ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS); > + ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI); > + ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT); > + ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI); > + } > + > + memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2); > + > + if (dev->BootFirmware) > + ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2); > + > + spin_lock_irq(&dev->cmd_lock); > + tmpCmdDoneByte = dev->ngenetohost + com->out_len; > + if (!com->out_len) > + tmpCmdDoneByte++; > + *tmpCmdDoneByte = 0; > + dev->ngenetohost[0] = 0; > + dev->ngenetohost[1] = 0; > + dev->CmdDoneByte = tmpCmdDoneByte; > + spin_unlock_irq(&dev->cmd_lock); > + > + /* Notify 8051. */ > + ngwritel(1, FORCE_INT); > + > + ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ); > + if (!ret) { > + /*ngwritel(0, FORCE_NMI);*/ > + > + printk(KERN_ERR DEVICE_NAME > + ": Command timeout cmd=%02x prev=%02x\n", > + com->cmd.hdr.Opcode, dev->prev_cmd); > + dump_command_io(dev); > + return -1; > + } > + if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) > + dev->BootFirmware = 0; > + > + dev->prev_cmd = com->cmd.hdr.Opcode; > + > + if (!com->out_len) > + return 0; > + > + memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len); > + > + return 0; > +} > + > +static int ngene_command(struct ngene *dev, struct ngene_command *com) > +{ > + int result; > + > + down(&dev->cmd_mutex); > + result = ngene_command_mutex(dev, com); > + up(&dev->cmd_mutex); > + return result; > +} > + > + > +static int ngene_command_i2c_read(struct ngene *dev, u8 adr, > + u8 *out, u8 outlen, u8 *in, u8 inlen, int flag) > +{ > + struct ngene_command com; > + > + com.cmd.hdr.Opcode = CMD_I2C_READ; > + com.cmd.hdr.Length = outlen + 3; > + com.cmd.I2CRead.Device = adr << 1; > + memcpy(com.cmd.I2CRead.Data, out, outlen); > + com.cmd.I2CRead.Data[outlen] = inlen; > + com.cmd.I2CRead.Data[outlen + 1] = 0; > + com.in_len = outlen + 3; > + com.out_len = inlen + 1; > + > + if (ngene_command(dev, &com) < 0) > + return -EIO; > + > + if ((com.cmd.raw8[0] >> 1) != adr) > + return -EIO; > + > + if (flag) > + memcpy(in, com.cmd.raw8, inlen + 1); > + else > + memcpy(in, com.cmd.raw8 + 1, inlen); > + return 0; > +} > + > +static int ngene_command_i2c_write(struct ngene *dev, u8 adr, > + u8 *out, u8 outlen) > +{ > + struct ngene_command com; > + > + > + com.cmd.hdr.Opcode = CMD_I2C_WRITE; > + com.cmd.hdr.Length = outlen + 1; > + com.cmd.I2CRead.Device = adr << 1; > + memcpy(com.cmd.I2CRead.Data, out, outlen); > + com.in_len = outlen + 1; > + com.out_len = 1; > + > + if (ngene_command(dev, &com) < 0) > + return -EIO; > + > + if (com.cmd.raw8[0] == 1) > + return -EIO; > + > + return 0; > +} > + > +static int ngene_command_load_firmware(struct ngene *dev, > + u8 *ngene_fw, u32 size) > +{ > +#define FIRSTCHUNK (1024) > + u32 cleft; > + struct ngene_command com; > + > + com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE; > + com.cmd.hdr.Length = 0; > + com.in_len = 0; > + com.out_len = 0; > + > + ngene_command(dev, &com); > + > + cleft = (size + 3) & ~3; > + if (cleft > FIRSTCHUNK) { > + ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK, > + cleft - FIRSTCHUNK); > + cleft = FIRSTCHUNK; > + } > + ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft); > + > + memset(&com, 0, sizeof(struct ngene_command)); > + com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH; > + com.cmd.hdr.Length = 4; > + com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA; > + com.cmd.FWLoadFinish.Length = (unsigned short)cleft; > + com.in_len = 4; > + com.out_len = 0; > + > + return ngene_command(dev, &com); > +} > + > + > +static int ngene_command_config_buf(struct ngene *dev, u8 config) > +{ > + struct ngene_command com; > + > + com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER; > + com.cmd.hdr.Length = 1; > + com.cmd.ConfigureBuffers.config = config; > + com.in_len = 1; > + com.out_len = 0; > + > + if (ngene_command(dev, &com) < 0) > + return -EIO; > + return 0; > +} > + > +static int ngene_command_config_free_buf(struct ngene *dev, u8 *config) > +{ > + struct ngene_command com; > + > + com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER; > + com.cmd.hdr.Length = 6; > + memcpy(&com.cmd.ConfigureBuffers.config, config, 6); > + com.in_len = 6; > + com.out_len = 0; > + > + if (ngene_command(dev, &com) < 0) > + return -EIO; > + > + return 0; > +} > + > +static int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level) > +{ > + struct ngene_command com; > + > + com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN; > + com.cmd.hdr.Length = 1; > + com.cmd.SetGpioPin.select = select | (level << 7); > + com.in_len = 1; > + com.out_len = 0; > + > + return ngene_command(dev, &com); > +} > + > + > +/* > + 02000640 is sample on rising edge. > + 02000740 is sample on falling edge. > + 02000040 is ignore "valid" signal > + > + 0: FD_CTL1 Bit 7,6 must be 0,1 > + 7 disable(fw controlled) > + 6 0-AUX,1-TS > + 5 0-par,1-ser > + 4 0-lsb/1-msb > + 3,2 reserved > + 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both > + 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge > + 2: FD_STA is read-only. 0-sync > + 3: FD_INSYNC is number of 47s to trigger "in sync". > + 4: FD_OUTSYNC is number of 47s to trigger "out of sync". > + 5: FD_MAXBYTE1 is low-order of bytes per packet. > + 6: FD_MAXBYTE2 is high-order of bytes per packet. > + 7: Top byte is unused. > +*/ > + > +/****************************************************************************/ > + > +static u8 TSFeatureDecoderSetup[8 * 4] = { > + 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, > + 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ > + 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ > + 0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ > +}; > + > +/* Set NGENE I2S Config to 16 bit packed */ > +static u8 I2SConfiguration[] = { > + 0x00, 0x10, 0x00, 0x00, > + 0x80, 0x10, 0x00, 0x00, > +}; > + > +static u8 SPDIFConfiguration[10] = { > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 > +}; > + > +/* Set NGENE I2S Config to transport stream compatible mode */ > + > +static u8 TS_I2SConfiguration[4] = { 0x3E, 0x1A, 0x00, 0x00 }; /*3e 18 00 00 ?*/ > + > +static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x20, 0x00, 0x00 }; > + > +static u8 ITUDecoderSetup[4][16] = { > + {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */ > + 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00}, > + {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, > + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, > + {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */ > + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, > + {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */ > + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, > +}; > + > +/* > + * 50 48 60 gleich > + * 27p50 9f 00 22 80 42 69 18 ... > + * 27p60 93 00 22 80 82 69 1c ... > + */ > + > +/* Maxbyte to 1144 (for raw data) */ > +static u8 ITUFeatureDecoderSetup[8] = { > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00 > +}; > + > +static void FillTSBuffer(void *Buffer, int Length, u32 Flags) > +{ > + u32 *ptr = Buffer; > + > + memset(Buffer, Length, 0xff); > + while (Length > 0) { > + if (Flags & DF_SWAP32) > + *ptr = 0x471FFF10; > + else > + *ptr = 0x10FF1F47; > + ptr += (188 / 4); > + Length -= 188; > + } > +} > + > + > +static void flush_buffers(struct ngene_channel *chan) > +{ > + u8 val; > + > + do { > + msleep(1); > + spin_lock_irq(&chan->state_lock); > + val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80; > + spin_unlock_irq(&chan->state_lock); > + } while (val); > +} > + > +static void clear_buffers(struct ngene_channel *chan) > +{ > + struct SBufferHeader *Cur = chan->nextBuffer; > + > + do { > + memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR)); > + if (chan->mode & NGENE_IO_TSOUT) > + FillTSBuffer(Cur->Buffer1, > + chan->Capture1Length, > + chan->DataFormatFlags); > + Cur = Cur->Next; > + } while (Cur != chan->nextBuffer); > + > + if (chan->mode & NGENE_IO_TSOUT) { > + chan->nextBuffer->ngeneBuffer.SR.DTOUpdate = > + chan->AudioDTOValue; > + chan->AudioDTOUpdated = 0; > + > + Cur = chan->TSIdleBuffer.Head; > + > + do { > + memset(&Cur->ngeneBuffer.SR, 0, > + sizeof(Cur->ngeneBuffer.SR)); > + FillTSBuffer(Cur->Buffer1, > + chan->Capture1Length, > + chan->DataFormatFlags); > + Cur = Cur->Next; > + } while (Cur != chan->TSIdleBuffer.Head); > + } > +} > + > +static int ngene_command_stream_control(struct ngene *dev, u8 stream, > + u8 control, u8 mode, u8 flags) > +{ > + struct ngene_channel *chan = &dev->channel[stream]; > + struct ngene_command com; > + u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); > + u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500); > + u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); > + u16 BsSDO = 0x9B00; > + > + /* down(&dev->stream_mutex); */ > + while (down_trylock(&dev->stream_mutex)) { > + printk(KERN_INFO DEVICE_NAME ": SC locked\n"); > + msleep(1); > + } > + memset(&com, 0, sizeof(com)); > + com.cmd.hdr.Opcode = CMD_CONTROL; > + com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; > + com.cmd.StreamControl.Stream = stream | (control ? 8 : 0); > + if (chan->mode & NGENE_IO_TSOUT) > + com.cmd.StreamControl.Stream |= 0x07; > + com.cmd.StreamControl.Control = control | > + (flags & SFLAG_ORDER_LUMA_CHROMA); > + com.cmd.StreamControl.Mode = mode; > + com.in_len = sizeof(struct FW_STREAM_CONTROL); > + com.out_len = 0; > + > + dprintk(KERN_INFO DEVICE_NAME > + ": Stream=%02x, Control=%02x, Mode=%02x\n", > + com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, > + com.cmd.StreamControl.Mode); > + > + chan->Mode = mode; > + > + if (!(control & 0x80)) { > + spin_lock_irq(&chan->state_lock); > + if (chan->State == KSSTATE_RUN) { > + chan->State = KSSTATE_ACQUIRE; > + chan->HWState = HWSTATE_STOP; > + spin_unlock_irq(&chan->state_lock); > + if (ngene_command(dev, &com) < 0) { > + up(&dev->stream_mutex); > + return -1; > + } > + /* clear_buffers(chan); */ > + flush_buffers(chan); > + up(&dev->stream_mutex); > + return 0; > + } > + spin_unlock_irq(&chan->state_lock); > + up(&dev->stream_mutex); > + return 0; > + } > + > + if (mode & SMODE_AUDIO_CAPTURE) { > + com.cmd.StreamControl.CaptureBlockCount = > + chan->Capture1Length / AUDIO_BLOCK_SIZE; > + com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; > + } else if (mode & SMODE_TRANSPORT_STREAM) { > + com.cmd.StreamControl.CaptureBlockCount = > + chan->Capture1Length / TS_BLOCK_SIZE; > + com.cmd.StreamControl.MaxLinesPerField = > + chan->Capture1Length / TS_BLOCK_SIZE; > + com.cmd.StreamControl.Buffer_Address = > + chan->TSRingBuffer.PAHead; > + if (chan->mode & NGENE_IO_TSOUT) { > + com.cmd.StreamControl.BytesPerVBILine = > + chan->Capture1Length / TS_BLOCK_SIZE; > + com.cmd.StreamControl.Stream |= 0x07; > + } > + } else { > + com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine; > + com.cmd.StreamControl.MaxLinesPerField = chan->nLines; > + com.cmd.StreamControl.MinLinesPerField = 100; > + com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; > + > + if (mode & SMODE_VBI_CAPTURE) { > + com.cmd.StreamControl.MaxVBILinesPerField = > + chan->nVBILines; > + com.cmd.StreamControl.MinVBILinesPerField = 0; > + com.cmd.StreamControl.BytesPerVBILine = > + chan->nBytesPerVBILine; > + } > + if (flags & SFLAG_COLORBAR) > + com.cmd.StreamControl.Stream |= 0x04; > + } > + > + spin_lock_irq(&chan->state_lock); > + if (mode & SMODE_AUDIO_CAPTURE) { > + chan->nextBuffer = chan->RingBuffer.Head; > + if (mode & SMODE_AUDIO_SPDIF) { > + com.cmd.StreamControl.SetupDataLen = > + sizeof(SPDIFConfiguration); > + com.cmd.StreamControl.SetupDataAddr = BsSPI; > + memcpy(com.cmd.StreamControl.SetupData, > + SPDIFConfiguration, sizeof(SPDIFConfiguration)); > + } else { > + com.cmd.StreamControl.SetupDataLen = 4; > + com.cmd.StreamControl.SetupDataAddr = BsSDI; > + memcpy(com.cmd.StreamControl.SetupData, > + I2SConfiguration + > + 4 * dev->card_info->i2s[stream], 4); > + } > + } else if (mode & SMODE_TRANSPORT_STREAM) { > + chan->nextBuffer = chan->TSRingBuffer.Head; > + if (stream >= STREAM_AUDIOIN1) { > + if (chan->mode & NGENE_IO_TSOUT) { > + com.cmd.StreamControl.SetupDataLen = > + sizeof(TS_I2SOutConfiguration); > + com.cmd.StreamControl.SetupDataAddr = BsSDO; > + memcpy(com.cmd.StreamControl.SetupData, > + TS_I2SOutConfiguration, > + sizeof(TS_I2SOutConfiguration)); > + } else { > + com.cmd.StreamControl.SetupDataLen = > + sizeof(TS_I2SConfiguration); > + com.cmd.StreamControl.SetupDataAddr = BsSDI; > + memcpy(com.cmd.StreamControl.SetupData, > + TS_I2SConfiguration, > + sizeof(TS_I2SConfiguration)); > + } > + } else { > + com.cmd.StreamControl.SetupDataLen = 8; > + com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10; > + memcpy(com.cmd.StreamControl.SetupData, > + TSFeatureDecoderSetup + > + 8 * dev->card_info->tsf[stream], 8); > + } > + } else { > + chan->nextBuffer = chan->RingBuffer.Head; > + com.cmd.StreamControl.SetupDataLen = > + 16 + sizeof(ITUFeatureDecoderSetup); > + com.cmd.StreamControl.SetupDataAddr = BsUVI; > + memcpy(com.cmd.StreamControl.SetupData, > + ITUDecoderSetup[chan->itumode], 16); > + memcpy(com.cmd.StreamControl.SetupData + 16, > + ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup)); > + } > + clear_buffers(chan); > + chan->State = KSSTATE_RUN; > + if (mode & SMODE_TRANSPORT_STREAM) > + chan->HWState = HWSTATE_RUN; > + else > + chan->HWState = HWSTATE_STARTUP; > + spin_unlock_irq(&chan->state_lock); > + > + if (ngene_command(dev, &com) < 0) { > + up(&dev->stream_mutex); > + return -1; > + } > + up(&dev->stream_mutex); > + return 0; > +} > + > + > +/****************************************************************************/ > +/* I2C **********************************************************************/ > +/****************************************************************************/ > + > +static void ngene_i2c_set_bus(struct ngene *dev, int bus) > +{ > + if (!(dev->card_info->i2c_access & 2)) > + return; > + if (dev->i2c_current_bus == bus) > + return; > + > + switch (bus) { > + case 0: > + ngene_command_gpio_set(dev, 3, 0); > + ngene_command_gpio_set(dev, 2, 1); > + break; > + > + case 1: > + ngene_command_gpio_set(dev, 2, 0); > + ngene_command_gpio_set(dev, 3, 1); > + break; > + } > + dev->i2c_current_bus = bus; > +} > + > +static int ngene_i2c_master_xfer(struct i2c_adapter *adapter, > + struct i2c_msg msg[], int num) > +{ > + struct ngene_channel *chan = > + (struct ngene_channel *)i2c_get_adapdata(adapter); > + struct ngene *dev = chan->dev; > + > + down(&dev->i2c_switch_mutex); > + ngene_i2c_set_bus(dev, chan->number); > + > + if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD)) > + if (!ngene_command_i2c_read(dev, msg[0].addr, > + msg[0].buf, msg[0].len, > + msg[1].buf, msg[1].len, 0)) > + goto done; > + > + if (num == 1 && !(msg[0].flags & I2C_M_RD)) > + if (!ngene_command_i2c_write(dev, msg[0].addr, > + msg[0].buf, msg[0].len)) > + goto done; > + if (num == 1 && (msg[0].flags & I2C_M_RD)) > + if (!ngene_command_i2c_read(dev, msg[0].addr, 0, 0, > + msg[0].buf, msg[0].len, 0)) > + goto done; > + > + up(&dev->i2c_switch_mutex); > + return -EIO; > + > +done: > + up(&dev->i2c_switch_mutex); > + return num; > +} > + > + > +static u32 ngene_i2c_functionality(struct i2c_adapter *adap) > +{ > + return I2C_FUNC_SMBUS_EMUL; > +} > + > +static struct i2c_algorithm ngene_i2c_algo = { > + .master_xfer = ngene_i2c_master_xfer, > + .functionality = ngene_i2c_functionality, > +}; > + > +static int ngene_i2c_init(struct ngene *dev, int dev_nr) > +{ > + struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter); > + > + i2c_set_adapdata(adap, &(dev->channel[dev_nr])); > +#ifdef I2C_ADAP_CLASS_TV_DIGITAL > + adap->class = I2C_ADAP_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG; > +#else > + adap->class = I2C_CLASS_TV_ANALOG; > +#endif This got renamed to I2C_CLASS_TV_DIGITAL. > + > + strcpy(adap->name, "nGene"); > + > + adap->algo = &ngene_i2c_algo; > + adap->algo_data = (void *)&(dev->channel[dev_nr]); > + adap->dev.parent = &dev->pci_dev->dev; > + > + mutex_init(&adap->bus_lock); > + return i2c_add_adapter(adap); > +} > + > + > +/****************************************************************************/ > +/* DVB functions and API interface ******************************************/ > +/****************************************************************************/ > + > +static void swap_buffer(u32 *p, u32 len) > +{ > + while (len) { > + *p = swab32(*p); > + p++; > + len -= 4; > + } > +} > + > + > +static void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) > +{ > + struct ngene_channel *chan = priv; > + > + > +#ifdef COMMAND_TIMEOUT_WORKAROUND > + if (chan->users > 0) > +#endif > + dvb_dmx_swfilter(&chan->demux, buf, len); > + return 0; > +} > + > +u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 }; > + > +static void *tsout_exchange(void *priv, void *buf, u32 len, > + u32 clock, u32 flags) > +{ > + struct ngene_channel *chan = priv; > + struct ngene *dev = chan->dev; > + u32 alen; > + > + alen = dvb_ringbuffer_avail(&dev->tsout_rbuf); > + alen -= alen % 188; > + > + if (alen < len) > + FillTSBuffer(buf + alen, len - alen, flags); > + else > + alen = len; > + dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen); > + if (flags & DF_SWAP32) > + swap_buffer((u32 *)buf, alen); > + wake_up_interruptible(&dev->tsout_rbuf.queue); > + return buf; > +} > + > + > +static void set_transfer(struct ngene_channel *chan, int state) > +{ > + u8 control = 0, mode = 0, flags = 0; > + struct ngene *dev = chan->dev; > + int ret; > + > + /* > + printk(KERN_INFO DEVICE_NAME ": st %d\n", state); > + msleep(100); > + */ > + > + if (state) { > + if (chan->running) { > + printk(KERN_INFO DEVICE_NAME ": already running\n"); > + return; > + } > + } else { > + if (!chan->running) { > + printk(KERN_INFO DEVICE_NAME ": already stopped\n"); > + return; > + } > + } > + > + if (dev->card_info->switch_ctrl) > + dev->card_info->switch_ctrl(chan, 1, state ^ 1); > + > + if (state) { > + spin_lock_irq(&chan->state_lock); > + > + /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", > + ngreadl(0x9310)); */ > + dvb_ringbuffer_flush(&dev->tsout_rbuf); > + control = 0x80; > + if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { > + chan->Capture1Length = 512 * 188; > + mode = SMODE_TRANSPORT_STREAM; > + } > + if (chan->mode & NGENE_IO_TSOUT) { > + chan->pBufferExchange = tsout_exchange; > + /* 0x66666666 = 50MHz *2^33 /250MHz */ > + chan->AudioDTOValue = 0x66666666; > + /* set_dto(chan, 38810700+1000); */ > + /* set_dto(chan, 19392658); */ > + } > + if (chan->mode & NGENE_IO_TSIN) > + chan->pBufferExchange = tsin_exchange; > + /* ngwritel(0, 0x9310); */ > + spin_unlock_irq(&chan->state_lock); > + } else > + ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", > + ngreadl(0x9310)); */ > + > + ret = ngene_command_stream_control(dev, chan->number, > + control, mode, flags); > + if (!ret) > + chan->running = state; > + else > + printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", > + state); > + if (!state) { > + spin_lock_irq(&chan->state_lock); > + chan->pBufferExchange = 0; > + dvb_ringbuffer_flush(&dev->tsout_rbuf); > + spin_unlock_irq(&chan->state_lock); > + } > +} > + > +static int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) > +{ > + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; > + struct ngene_channel *chan = dvbdmx->priv; > + > + if (chan->users == 0) { > +#ifdef COMMAND_TIMEOUT_WORKAROUND > + if (!chan->running) > +#endif > + set_transfer(chan, 1); > + /* msleep(10); */ > + } > + > + return ++chan->users; > +} > + > +static int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) > +{ > + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; > + struct ngene_channel *chan = dvbdmx->priv; > + > + if (--chan->users) > + return chan->users; > + > +#ifndef COMMAND_TIMEOUT_WORKAROUND > + set_transfer(chan, 0); > +#endif > + > + return 0; > +} > + > + > + > +static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, > + int (*start_feed)(struct dvb_demux_feed *), > + int (*stop_feed)(struct dvb_demux_feed *), > + void *priv) > +{ > + dvbdemux->priv = priv; > + > + dvbdemux->filternum = 256; > + dvbdemux->feednum = 256; > + dvbdemux->start_feed = start_feed; > + dvbdemux->stop_feed = stop_feed; > + dvbdemux->write_to_decoder = 0; > + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | > + DMX_SECTION_FILTERING | > + DMX_MEMORY_BASED_FILTERING); > + return dvb_dmx_init(dvbdemux); > +} > + > +static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, > + struct dvb_demux *dvbdemux, > + struct dmx_frontend *hw_frontend, > + struct dmx_frontend *mem_frontend, > + struct dvb_adapter *dvb_adapter) > +{ > + int ret; > + > + dmxdev->filternum = 256; > + dmxdev->demux = &dvbdemux->dmx; > + dmxdev->capabilities = 0; > + ret = dvb_dmxdev_init(dmxdev, dvb_adapter); > + if (ret < 0) > + return ret; > + > + hw_frontend->source = DMX_FRONTEND_0; > + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); > + mem_frontend->source = DMX_MEMORY_FE; > + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); > + return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); > +} > + > + > +/****************************************************************************/ > +/* nGene hardware init and release functions ********************************/ > +/****************************************************************************/ > + > +static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb) > +{ > + struct SBufferHeader *Cur = rb->Head; > + u32 j; > + > + if (!Cur) > + return; > + > + for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) { > + if (Cur->Buffer1) > + pci_free_consistent(dev->pci_dev, > + rb->Buffer1Length, > + Cur->Buffer1, > + Cur->scList1->Address); > + > + if (Cur->Buffer2) > + pci_free_consistent(dev->pci_dev, > + rb->Buffer2Length, > + Cur->Buffer2, > + Cur->scList2->Address); > + } > + > + if (rb->SCListMem) > + pci_free_consistent(dev->pci_dev, rb->SCListMemSize, > + rb->SCListMem, rb->PASCListMem); > + > + pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead); > +} > + > +static void free_idlebuffer(struct ngene *dev, > + struct SRingBufferDescriptor *rb, > + struct SRingBufferDescriptor *tb) > +{ > + int j; > + struct SBufferHeader *Cur = tb->Head; > + > + if (!rb->Head) > + return; > + free_ringbuffer(dev, rb); > + for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) { > + Cur->Buffer2 = 0; > + Cur->scList2 = 0; > + Cur->ngeneBuffer.Address_of_first_entry_2 = 0; > + Cur->ngeneBuffer.Number_of_entries_2 = 0; > + } > +} > + > +static void free_common_buffers(struct ngene *dev) > +{ > + u32 i; > + struct ngene_channel *chan; > + > + for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { > + chan = &dev->channel[i]; > + free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer); > + free_ringbuffer(dev, &chan->RingBuffer); > + free_ringbuffer(dev, &chan->TSRingBuffer); > + } > + > + if (dev->OverflowBuffer) > + pci_free_consistent(dev->pci_dev, > + OVERFLOW_BUFFER_SIZE, > + dev->OverflowBuffer, dev->PAOverflowBuffer); > + > + if (dev->FWInterfaceBuffer) > + pci_free_consistent(dev->pci_dev, > + 4096, > + dev->FWInterfaceBuffer, > + dev->PAFWInterfaceBuffer); > +} > + > +/****************************************************************************/ > +/* Ring buffer handling *****************************************************/ > +/****************************************************************************/ > + > +static int create_ring_buffer(struct pci_dev *pci_dev, > + struct SRingBufferDescriptor *descr, u32 NumBuffers) > +{ > + dma_addr_t tmp; > + struct SBufferHeader *Head; > + u32 i; > + u32 MemSize = SIZEOF_SBufferHeader * NumBuffers; > + u64 PARingBufferHead; > + u64 PARingBufferCur; > + u64 PARingBufferNext; > + struct SBufferHeader *Cur, *Next; > + > + descr->Head = 0; > + descr->MemSize = 0; > + descr->PAHead = 0; > + descr->NumBuffers = 0; > + > + if (MemSize < 4096) > + MemSize = 4096; > + > + Head = pci_alloc_consistent(pci_dev, MemSize, &tmp); > + PARingBufferHead = tmp; > + > + if (!Head) > + return -ENOMEM; > + > + memset(Head, 0, MemSize); > + > + PARingBufferCur = PARingBufferHead; > + Cur = Head; > + > + for (i = 0; i < NumBuffers - 1; i++) { > + Next = (struct SBufferHeader *) > + (((u8 *) Cur) + SIZEOF_SBufferHeader); > + PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader; > + Cur->Next = Next; > + Cur->ngeneBuffer.Next = PARingBufferNext; > + Cur = Next; > + PARingBufferCur = PARingBufferNext; > + } > + /* Last Buffer points back to first one */ > + Cur->Next = Head; > + Cur->ngeneBuffer.Next = PARingBufferHead; > + > + descr->Head = Head; > + descr->MemSize = MemSize; > + descr->PAHead = PARingBufferHead; > + descr->NumBuffers = NumBuffers; > + > + return 0; > +} > + > +static int AllocateRingBuffers(struct pci_dev *pci_dev, > + dma_addr_t of, > + struct SRingBufferDescriptor *pRingBuffer, > + u32 Buffer1Length, u32 Buffer2Length) > +{ > + dma_addr_t tmp; > + u32 i, j; > + int status = 0; > + u32 SCListMemSize = pRingBuffer->NumBuffers > + * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) : > + NUM_SCATTER_GATHER_ENTRIES) > + * sizeof(struct HW_SCATTER_GATHER_ELEMENT); > + > + u64 PASCListMem; > + PHW_SCATTER_GATHER_ELEMENT SCListEntry; > + u64 PASCListEntry; > + struct SBufferHeader *Cur; > + void *SCListMem; > + > + if (SCListMemSize < 4096) > + SCListMemSize = 4096; > + > + SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp); > + > + PASCListMem = tmp; > + if (SCListMem == NULL) > + return -ENOMEM; > + > + memset(SCListMem, 0, SCListMemSize); > + > + pRingBuffer->SCListMem = SCListMem; > + pRingBuffer->PASCListMem = PASCListMem; > + pRingBuffer->SCListMemSize = SCListMemSize; > + pRingBuffer->Buffer1Length = Buffer1Length; > + pRingBuffer->Buffer2Length = Buffer2Length; > + > + SCListEntry = (PHW_SCATTER_GATHER_ELEMENT) SCListMem; > + PASCListEntry = PASCListMem; > + Cur = pRingBuffer->Head; > + > + for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) { > + u64 PABuffer; > + > + void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length, > + &tmp); > + PABuffer = tmp; > + > + if (Buffer == NULL) > + return -ENOMEM; > + > + Cur->Buffer1 = Buffer; > + > + SCListEntry->Address = PABuffer; > + SCListEntry->Length = Buffer1Length; > + > + Cur->scList1 = SCListEntry; > + Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry; > + Cur->ngeneBuffer.Number_of_entries_1 = > + NUM_SCATTER_GATHER_ENTRIES; > + > + SCListEntry += 1; Instead: SCListEntry++; > + PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); > + > +#if NUM_SCATTER_GATHER_ENTRIES > 1 > + for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) { j++, instead of j +=1 > + SCListEntry->Address = of; > + SCListEntry->Length = OVERFLOW_BUFFER_SIZE; > + SCListEntry += 1; > + PASCListEntry += > + sizeof(struct HW_SCATTER_GATHER_ELEMENT); > + } > +#endif The number of Scatter/Gather entries is 8. Even if you use #define NUM_SCATTER_GATHER_ENTRIES 1, the above code won't cause any harm (except maybe for a compiler warning - that seems healthy in this case). So, I think you can just remove the #if test. While here: the better is to write the loop increment as j++, instead of j+= 1: for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) { The same kind of bad coding style also happens on other parts of the code. I'll avoid being redundant on this. > + > + if (!Buffer2Length) > + continue; > + > + Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp); > + PABuffer = tmp; > + > + if (Buffer == NULL) > + return -ENOMEM; > + > + Cur->Buffer2 = Buffer; > + > + SCListEntry->Address = PABuffer; > + SCListEntry->Length = Buffer2Length; > + > + Cur->scList2 = SCListEntry; > + Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry; > + Cur->ngeneBuffer.Number_of_entries_2 = > + NUM_SCATTER_GATHER_ENTRIES; > + > + SCListEntry += 1; > + PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); > + > +#if NUM_SCATTER_GATHER_ENTRIES > 1 > + for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) { > + SCListEntry->Address = of; > + SCListEntry->Length = OVERFLOW_BUFFER_SIZE; > + SCListEntry += 1; > + PASCListEntry += > + sizeof(struct HW_SCATTER_GATHER_ELEMENT); > + } > +#endif > + > + } > + > + return status; > +} > + > +static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer, > + struct SRingBufferDescriptor *pRingBuffer) > +{ > + int status = 0; > + > + /* Copy pointer to scatter gather list in TSRingbuffer > + structure for buffer 2 > + Load number of buffer > + */ > + u32 n = pRingBuffer->NumBuffers; > + > + /* Point to first buffer entry */ > + struct SBufferHeader *Cur = pRingBuffer->Head; > + int i; > + /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */ > + for (i = 0; i < n; i++) { > + Cur->Buffer2 = pIdleBuffer->Head->Buffer1; > + Cur->scList2 = pIdleBuffer->Head->scList1; > + Cur->ngeneBuffer.Address_of_first_entry_2 = > + pIdleBuffer->Head->ngeneBuffer. > + Address_of_first_entry_1; > + Cur->ngeneBuffer.Number_of_entries_2 = > + pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1; > + Cur = Cur->Next; > + } > + return status; > +} > + > +static u32 RingBufferSizes[MAX_STREAM] = { > + RING_SIZE_VIDEO, > + RING_SIZE_VIDEO, > + RING_SIZE_AUDIO, > + RING_SIZE_AUDIO, > + RING_SIZE_AUDIO, > +}; > + > +static u32 Buffer1Sizes[MAX_STREAM] = { > + MAX_VIDEO_BUFFER_SIZE, > + MAX_VIDEO_BUFFER_SIZE, > + MAX_AUDIO_BUFFER_SIZE, > + MAX_AUDIO_BUFFER_SIZE, > + MAX_AUDIO_BUFFER_SIZE > +}; > + > +static u32 Buffer2Sizes[MAX_STREAM] = { > + MAX_VBI_BUFFER_SIZE, > + MAX_VBI_BUFFER_SIZE, > + 0, > + 0, > + 0 > +}; > + > + > +static int AllocCommonBuffers(struct ngene *dev) > +{ > + int status = 0, i; > + > + dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096, > + &dev->PAFWInterfaceBuffer); > + if (!dev->FWInterfaceBuffer) > + return -ENOMEM; > + dev->hosttongene = dev->FWInterfaceBuffer; > + dev->ngenetohost = dev->FWInterfaceBuffer + 256; > + dev->EventBuffer = dev->FWInterfaceBuffer + 512; > + > + dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev, > + OVERFLOW_BUFFER_SIZE, > + &dev->PAOverflowBuffer); > + if (!dev->OverflowBuffer) > + return -ENOMEM; > + memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE); > + > + for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { > + int type = dev->card_info->io_type[i]; > + > + dev->channel[i].State = KSSTATE_STOP; > + > + if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) { > + status = create_ring_buffer(dev->pci_dev, > + &dev->channel[i].RingBuffer, > + RingBufferSizes[i]); > + if (status < 0) > + break; > + > + if (type & (NGENE_IO_TV | NGENE_IO_AIN)) { > + status = AllocateRingBuffers(dev->pci_dev, > + dev-> > + PAOverflowBuffer, > + &dev->channel[i]. > + RingBuffer, > + Buffer1Sizes[i], > + Buffer2Sizes[i]); > + if (status < 0) > + break; > + } else if (type & NGENE_IO_HDTV) { > + status = AllocateRingBuffers(dev->pci_dev, > + dev-> > + PAOverflowBuffer, > + &dev->channel[i]. > + RingBuffer, > + MAX_HDTV_BUFFER_SIZE, > + 0); > + if (status < 0) > + break; > + } > + } > + > + if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { > + > + status = create_ring_buffer(dev->pci_dev, > + &dev->channel[i]. > + TSRingBuffer, RING_SIZE_TS); > + if (status < 0) > + break; > + > + status = AllocateRingBuffers(dev->pci_dev, > + dev->PAOverflowBuffer, > + &dev->channel[i]. > + TSRingBuffer, > + MAX_TS_BUFFER_SIZE, 0); > + if (status) > + break; > + } > + > + if (type & NGENE_IO_TSOUT) { > + status = create_ring_buffer(dev->pci_dev, > + &dev->channel[i]. > + TSIdleBuffer, 1); > + if (status < 0) > + break; > + status = AllocateRingBuffers(dev->pci_dev, > + dev->PAOverflowBuffer, > + &dev->channel[i]. > + TSIdleBuffer, > + MAX_TS_BUFFER_SIZE, 0); > + if (status) > + break; > + FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer, > + &dev->channel[i].TSRingBuffer); > + } > + } > + return status; > +} > + > +static void ngene_release_buffers(struct ngene *dev) > +{ > + if (dev->iomem) > + iounmap(dev->iomem); > + free_common_buffers(dev); > + vfree(dev->tsout_buf); > + vfree(dev->ain_buf); > + vfree(dev->vin_buf); > + vfree(dev); > +} > + > +static int ngene_get_buffers(struct ngene *dev) > +{ > + if (AllocCommonBuffers(dev)) > + return -ENOMEM; > + if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) { > + dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE); > + if (!dev->tsout_buf) > + return -ENOMEM; > + dvb_ringbuffer_init(&dev->tsout_rbuf, > + dev->tsout_buf, TSOUT_BUF_SIZE); > + } > + if (dev->card_info->io_type[2] & NGENE_IO_AIN) { > + dev->ain_buf = vmalloc(AIN_BUF_SIZE); > + if (!dev->ain_buf) > + return -ENOMEM; > + dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE); > + } > + if (dev->card_info->io_type[0] & NGENE_IO_HDTV) { > + dev->vin_buf = vmalloc(VIN_BUF_SIZE); > + if (!dev->vin_buf) > + return -ENOMEM; > + dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE); > + } > + dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0), > + pci_resource_len(dev->pci_dev, 0)); > + if (!dev->iomem) > + return -ENOMEM; > + > + return 0; > +} > + > +static void ngene_init(struct ngene *dev) > +{ > + int i; > + > + tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); > + > + memset_io(dev->iomem + 0xc000, 0x00, 0x220); > + memset_io(dev->iomem + 0xc400, 0x00, 0x100); > + > + for (i = 0; i < MAX_STREAM; i++) { > + dev->channel[i].dev = dev; > + dev->channel[i].number = i; > + } > + > + dev->fw_interface_version = 0; > + > + ngwritel(0, NGENE_INT_ENABLE); > + > + dev->icounts = ngreadl(NGENE_INT_COUNTS); > + > + dev->device_version = ngreadl(DEV_VER) & 0x0f; > + printk(KERN_INFO DEVICE_NAME ": Device version %d\n", > + dev->device_version); > +} > + > +static int ngene_load_firm(struct ngene *dev) > +{ > + u32 size; > + const struct firmware *fw = NULL; > + u8 *ngene_fw; > + char *fw_name; > + int err, version; > + > + version = dev->card_info->fw_version; > + > + switch (version) { > + default: > + case 15: > + version = 15; > + size = 23466; > + fw_name = "ngene_15.fw"; > + break; > + case 16: > + size = 23498; > + fw_name = "ngene_16.fw"; > + break; > + case 17: > + size = 24446; > + fw_name = "ngene_17.fw"; > + break; > + } > + > + if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { > + printk(KERN_ERR DEVICE_NAME > + ": Could not load firmware file %s.\n", fw_name); > + printk(KERN_INFO DEVICE_NAME > + ": Copy %s to your hotplug directory!\n", fw_name); > + return -1; > + } > + if (size != fw->size) { > + printk(KERN_ERR DEVICE_NAME > + ": Firmware %s has invalid size!", fw_name); > + err = -1; > + } else { > + printk(KERN_INFO DEVICE_NAME > + ": Loading firmware file %s.\n", fw_name); > + ngene_fw = (u8 *) fw->data; > + err = ngene_command_load_firmware(dev, ngene_fw, size); > + } > + > + release_firmware(fw); > + > + return err; > +} > + > +static void ngene_stop(struct ngene *dev) > +{ > + down(&dev->cmd_mutex); > + i2c_del_adapter(&(dev->channel[0].i2c_adapter)); > + i2c_del_adapter(&(dev->channel[1].i2c_adapter)); > + ngwritel(0, NGENE_INT_ENABLE); > + ngwritel(0, NGENE_COMMAND); > + ngwritel(0, NGENE_COMMAND_HI); > + ngwritel(0, NGENE_STATUS); > + ngwritel(0, NGENE_STATUS_HI); > + ngwritel(0, NGENE_EVENT); > + ngwritel(0, NGENE_EVENT_HI); > + free_irq(dev->pci_dev->irq, dev); > +} > + > +static int ngene_start(struct ngene *dev) > +{ > + int stat; > + int i; > + > + pci_set_master(dev->pci_dev); > + ngene_init(dev); > + > + stat = request_irq(dev->pci_dev->irq, irq_handler, > + IRQF_SHARED, "nGene", > + (void *)dev); > + if (stat < 0) > + return stat; > + > + init_waitqueue_head(&dev->cmd_wq); > + init_waitqueue_head(&dev->tx_wq); > + init_waitqueue_head(&dev->rx_wq); > + sema_init(&dev->cmd_mutex, 1); > + sema_init(&dev->stream_mutex, 1); > + sema_init(&dev->pll_mutex, 1); > + sema_init(&dev->i2c_switch_mutex, 1); > + spin_lock_init(&dev->cmd_lock); > + for (i = 0; i < MAX_STREAM; i++) > + spin_lock_init(&dev->channel[i].state_lock); > + ngwritel(1, TIMESTAMPS); > + > + ngwritel(1, NGENE_INT_ENABLE); > + > + stat = ngene_load_firm(dev); > + if (stat < 0) > + goto fail; > + > + stat = ngene_i2c_init(dev, 0); > + if (stat < 0) > + goto fail; > + > + stat = ngene_i2c_init(dev, 1); > + if (stat < 0) > + goto fail; > + > + if (dev->card_info->fw_version == 17) { > + u8 tsin4_config[6] = > + {3072 / 64, 3072 / 64, 0, 3072 / 64, 3072 / 64, 0}; > + u8 default_config[6] = > + {4096 / 64, 4096 / 64, 0, 2048 / 64, 2048 / 64, 0}; > + u8 *bconf = default_config; > + > + if (dev->card_info->io_type[3] == NGENE_IO_TSIN) > + bconf = tsin4_config; > + dprintk(KERN_DEBUG DEVICE_NAME ": FW 17 buffer config\n"); > + stat = ngene_command_config_free_buf(dev, bconf); > + } else { > + int bconf = BUFFER_CONFIG_4422; > + if (dev->card_info->io_type[3] == NGENE_IO_TSIN) > + bconf = BUFFER_CONFIG_3333; > + stat = ngene_command_config_buf(dev, bconf); > + } > + return stat; > +fail: > + ngwritel(0, NGENE_INT_ENABLE); > + free_irq(dev->pci_dev->irq, dev); > + return stat; > +} > + > + > + > +/****************************************************************************/ > +/* Switch control (I2C gates, etc.) *****************************************/ > +/****************************************************************************/ > + > + > +/****************************************************************************/ > +/* Demod/tuner attachment ***************************************************/ > +/****************************************************************************/ > + > +static int tuner_attach_stv6110(struct ngene_channel *chan) > +{ > + struct stv090x_config *feconf = (struct stv090x_config *) > + chan->dev->card_info->fe_config[chan->number]; > + struct stv6110x_config *tunerconf = (struct stv6110x_config *) > + chan->dev->card_info->tuner_config[chan->number]; > + struct stv6110x_devctl *ctl; > + > + ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, > + &chan->i2c_adapter); > + if (ctl == NULL) { > + printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); > + return -ENODEV; > + } > + > + feconf->tuner_init = ctl->tuner_init; > + feconf->tuner_set_mode = ctl->tuner_set_mode; > + feconf->tuner_set_frequency = ctl->tuner_set_frequency; > + feconf->tuner_get_frequency = ctl->tuner_get_frequency; > + feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; > + feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; > + feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; > + feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; > + feconf->tuner_set_refclk = ctl->tuner_set_refclk; > + feconf->tuner_get_status = ctl->tuner_get_status; > + > + return 0; > +} > + > + > +static int demod_attach_stv0900(struct ngene_channel *chan) > +{ > + struct stv090x_config *feconf = (struct stv090x_config *) > + chan->dev->card_info->fe_config[chan->number]; > + > + chan->fe = dvb_attach(stv090x_attach, > + feconf, > + &chan->i2c_adapter, > + chan->number == 0 ? STV090x_DEMODULATOR_0 : > + STV090x_DEMODULATOR_1); > + if (chan->fe == NULL) { > + printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); > + return -ENODEV; > + } > + > + if (!dvb_attach(lnbh24_attach, chan->fe, &chan->i2c_adapter, 0, > + 0, chan->dev->card_info->lnb[chan->number])) { > + printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); > + dvb_frontend_detach(chan->fe); > + return -ENODEV; > + } > + > + return 0; > +} > + > +/****************************************************************************/ > +/****************************************************************************/ > +/****************************************************************************/ > + > +static void release_channel(struct ngene_channel *chan) > +{ > + struct dvb_demux *dvbdemux = &chan->demux; > + struct ngene *dev = chan->dev; > + struct ngene_info *ni = dev->card_info; > + int io = ni->io_type[chan->number]; > + > +#ifdef COMMAND_TIMEOUT_WORKAROUND > + if (chan->running) > + set_transfer(chan, 0); > +#endif > + > + tasklet_kill(&chan->demux_tasklet); > + > + if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { > + if (chan->fe) { > + dvb_unregister_frontend(chan->fe); > + dvb_frontend_detach(chan->fe); > + chan->fe = 0; > + } > + dvbdemux->dmx.close(&dvbdemux->dmx); > + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, > + &chan->hw_frontend); > + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, > + &chan->mem_frontend); > + dvb_dmxdev_release(&chan->dmxdev); > + dvb_dmx_release(&chan->demux); > + > + if (chan->number == 0 || !one_adapter) > + dvb_unregister_adapter(&dev->adapter[chan->number]); > + } > +} > + > +static int init_channel(struct ngene_channel *chan) > +{ > + int ret = 0, nr = chan->number; > + struct dvb_adapter *adapter = NULL; > + struct dvb_demux *dvbdemux = &chan->demux; > + struct ngene *dev = chan->dev; > + struct ngene_info *ni = dev->card_info; > + int io = ni->io_type[nr]; > + > + tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan); > + chan->users = 0; > + chan->type = io; > + chan->mode = chan->type; /* for now only one mode */ > + > + if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { > + if (nr >= STREAM_AUDIOIN1) > + chan->DataFormatFlags = DF_SWAP32; > + if (nr == 0 || !one_adapter) { > + adapter = &dev->adapter[nr]; > + ret = dvb_register_adapter(adapter, "nGene", > + THIS_MODULE, > + &chan->dev->pci_dev->dev, > + adapter_nr); > + if (ret < 0) > + return ret; > + } else { > + adapter = &dev->adapter[0]; > + } > + > + ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", > + ngene_start_feed, > + ngene_stop_feed, chan); > + ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, > + &chan->hw_frontend, > + &chan->mem_frontend, adapter); > + } > + > + if (io & NGENE_IO_TSIN) { > + chan->fe = NULL; > + if (ni->demod_attach[nr]) > + ni->demod_attach[nr](chan); > + if (chan->fe) { > + if (dvb_register_frontend(adapter, chan->fe) < 0) { > + if (chan->fe->ops.release) > + chan->fe->ops.release(chan->fe); > + chan->fe = NULL; > + } > + } > + if (chan->fe && ni->tuner_attach[nr]) > + if (ni->tuner_attach[nr] (chan) < 0) { > + printk(KERN_ERR DEVICE_NAME > + ": Tuner attach failed on channel %d!\n", > + nr); > + } > + } > + return ret; > +} > + > +static int init_channels(struct ngene *dev) > +{ > + int i, j; > + > + for (i = 0; i < MAX_STREAM; i++) { > + if (init_channel(&dev->channel[i]) < 0) { > + for (j = i - 1; j >= 0; j--) > + release_channel(&dev->channel[j]); > + return -1; > + } > + } > + return 0; > +} > + > +/****************************************************************************/ > +/* device probe/remove calls ************************************************/ > +/****************************************************************************/ > + > +static void __devexit ngene_remove(struct pci_dev *pdev) > +{ > + struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev); > + int i; > + > + tasklet_kill(&dev->event_tasklet); > + for (i = MAX_STREAM - 1; i >= 0; i--) > + release_channel(&dev->channel[i]); > + ngene_stop(dev); > + ngene_release_buffers(dev); > + pci_set_drvdata(pdev, 0); > + pci_disable_device(pdev); > +} > + > +static int __devinit ngene_probe(struct pci_dev *pci_dev, > + const struct pci_device_id *id) > +{ > + struct ngene *dev; > + int stat = 0; > + > + if (pci_enable_device(pci_dev) < 0) > + return -ENODEV; > + > + dev = vmalloc(sizeof(struct ngene)); > + if (dev == NULL) { > + stat = -ENOMEM; > + goto fail0; > + } > + memset(dev, 0, sizeof(struct ngene)); > + > + dev->pci_dev = pci_dev; > + dev->card_info = (struct ngene_info *)id->driver_data; > + printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); > + > + pci_set_drvdata(pci_dev, dev); > + > + /* Alloc buffers and start nGene */ > + stat = ngene_get_buffers(dev); > + if (stat < 0) > + goto fail1; > + stat = ngene_start(dev); > + if (stat < 0) > + goto fail1; > + > + dev->i2c_current_bus = -1; > + > + /* Register DVB adapters and devices for both channels */ > + if (init_channels(dev) < 0) > + goto fail2; > + > + return 0; > + > +fail2: > + ngene_stop(dev); > +fail1: > + ngene_release_buffers(dev); > +fail0: > + pci_disable_device(pci_dev); > + pci_set_drvdata(pci_dev, 0); > + return stat; > +} > + > +/****************************************************************************/ > +/* Card configs *************************************************************/ > +/****************************************************************************/ > + > +static struct stv090x_config fe_cineS2 = { > + .device = STV0900, > + .demod_mode = STV090x_DUAL, > + .clk_mode = STV090x_CLK_EXT, > + > + .xtal = 27000000, > + .address = 0x68, > + > + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, > + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, > + > + .repeater_level = STV090x_RPTLEVEL_16, > + > + .adc1_range = STV090x_ADC_1Vpp, > + .adc2_range = STV090x_ADC_1Vpp, > + > + .diseqc_envelope_mode = true, > +}; > + > +static struct stv6110x_config tuner_cineS2_0 = { > + .addr = 0x60, > + .refclk = 27000000, > + .clk_div = 1, > +}; > + > +static struct stv6110x_config tuner_cineS2_1 = { > + .addr = 0x63, > + .refclk = 27000000, > + .clk_div = 1, > +}; > + > +static struct ngene_info ngene_info_cineS2 = { > + .type = NGENE_SIDEWINDER, > + .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", > + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, > + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, > + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, > + .fe_config = {&fe_cineS2, &fe_cineS2}, > + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, > + .lnb = {0x0b, 0x08}, > + .tsf = {3, 3}, > + .fw_version = 15, > +}; > + > +static struct ngene_info ngene_info_satixs2 = { > + .type = NGENE_SIDEWINDER, > + .name = "Mystique SaTiX-S2 Dual", > + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, > + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, > + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, > + .fe_config = {&fe_cineS2, &fe_cineS2}, > + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, > + .lnb = {0x0b, 0x08}, > + .tsf = {3, 3}, > + .fw_version = 15, > +}; > + > +/****************************************************************************/ > + > + > + > +/****************************************************************************/ > +/* PCI Subsystem ID *********************************************************/ > +/****************************************************************************/ > + > +#define NGENE_ID(_subvend, _subdev, _driverdata) { \ > + .vendor = NGENE_VID, .device = NGENE_PID, \ > + .subvendor = _subvend, .subdevice = _subdev, \ > + .driver_data = (unsigned long) &_driverdata } > + > +/****************************************************************************/ > + > +static const struct pci_device_id ngene_id_tbl[] __devinitdata = { > + NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), > + NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), > + NGENE_ID(0x18c3, 0xdb01, ngene_info_satixs2), > + {0} just {} is enough. > +}; > +MODULE_DEVICE_TABLE(pci, ngene_id_tbl); > + > +/****************************************************************************/ > +/* Init/Exit ****************************************************************/ > +/****************************************************************************/ > + > +static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, > + enum pci_channel_state state) > +{ > + printk(KERN_ERR DEVICE_NAME ": PCI error\n"); > + if (state == pci_channel_io_perm_failure) > + return PCI_ERS_RESULT_DISCONNECT; > + if (state == pci_channel_io_frozen) > + return PCI_ERS_RESULT_NEED_RESET; > + return PCI_ERS_RESULT_CAN_RECOVER; > +} > + > +static pci_ers_result_t ngene_link_reset(struct pci_dev *dev) > +{ > + printk(KERN_INFO DEVICE_NAME ": link reset\n"); > + return 0; > +} > + > +static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) > +{ > + printk(KERN_INFO DEVICE_NAME ": slot reset\n"); > + return 0; > +} > + > +static void ngene_resume(struct pci_dev *dev) > +{ > + printk(KERN_INFO DEVICE_NAME ": resume\n"); > +} > + > +static struct pci_error_handlers ngene_errors = { > + .error_detected = ngene_error_detected, > + .link_reset = ngene_link_reset, > + .slot_reset = ngene_slot_reset, > + .resume = ngene_resume, > +}; > + > +static struct pci_driver ngene_pci_driver = { > + .name = "ngene", > + .id_table = ngene_id_tbl, > + .probe = ngene_probe, > + .remove = __devexit_p(ngene_remove), > + .err_handler = &ngene_errors, > +}; > + > +static __init int module_init_ngene(void) > +{ > + printk(KERN_INFO > + "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); > + return pci_register_driver(&ngene_pci_driver); > +} > + > +static __exit void module_exit_ngene(void) > +{ > + pci_unregister_driver(&ngene_pci_driver); > +} > + > +module_init(module_init_ngene); > +module_exit(module_exit_ngene); > + > +MODULE_DESCRIPTION("nGene"); > +MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h > new file mode 100644 > index 0000000..1c6f0e7 > --- /dev/null > +++ b/drivers/media/dvb/ngene/ngene.h > @@ -0,0 +1,864 @@ > +/* > + * ngene.h: nGene PCIe bridge driver > + * > + * Copyright (C) 2005-2007 Micronas > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * version 2 only, as published by the Free Software Foundation. > + * > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > + * 02110-1301, USA > + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html > + */ > + > +#ifndef _NGENE_H_ > +#define _NGENE_H_ > + > +#include <linux/types.h> > +#include <linux/sched.h> > +#include <linux/interrupt.h> > +#include <linux/i2c.h> > +#include <asm/dma.h> > +#include <asm/scatterlist.h> > + > +#include <linux/dvb/frontend.h> > + > +#include "dmxdev.h" > +#include "dvbdev.h" > +#include "dvb_demux.h" > +#include "dvb_frontend.h" > +#include "dvb_ringbuffer.h" > + > +#define NGENE_VID 0x18c3 > +#define NGENE_PID 0x0720 > + > +#ifndef VIDEO_CAP_VC1 > +#define VIDEO_CAP_AVC 128 > +#define VIDEO_CAP_H264 128 > +#define VIDEO_CAP_VC1 256 > +#define VIDEO_CAP_WMV9 256 > +#define VIDEO_CAP_MPEG4 512 > +#endif > + > +enum STREAM { > + STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ > + STREAM_VIDEOIN2, > + STREAM_AUDIOIN1, /* I2S or SPI Input */ > + STREAM_AUDIOIN2, > + STREAM_AUDIOOUT, > + MAX_STREAM > +}; > + > +enum SMODE_BITS { > + SMODE_AUDIO_SPDIF = 0x20, > + SMODE_AVSYNC = 0x10, > + SMODE_TRANSPORT_STREAM = 0x08, > + SMODE_AUDIO_CAPTURE = 0x04, > + SMODE_VBI_CAPTURE = 0x02, > + SMODE_VIDEO_CAPTURE = 0x01 > +}; > + > +enum STREAM_FLAG_BITS { > + SFLAG_CHROMA_FORMAT_2COMP = 0x01, /* Chroma Format : 2's complement */ > + SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */ > + SFLAG_ORDER_LUMA_CHROMA = 0x02, /* Byte order: Y,Cb,Y,Cr */ > + SFLAG_ORDER_CHROMA_LUMA = 0x00, /* Byte order: Cb,Y,Cr,Y */ > + SFLAG_COLORBAR = 0x04, /* Select colorbar */ > +}; > + > +#define PROGRAM_ROM 0x0000 > +#define PROGRAM_SRAM 0x1000 > +#define PERIPHERALS0 0x8000 > +#define PERIPHERALS1 0x9000 > +#define SHARED_BUFFER 0xC000 > + > +#define HOST_TO_NGENE (SHARED_BUFFER+0x0000) > +#define NGENE_TO_HOST (SHARED_BUFFER+0x0100) > +#define NGENE_COMMAND (SHARED_BUFFER+0x0200) > +#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204) > +#define NGENE_STATUS (SHARED_BUFFER+0x0208) > +#define NGENE_STATUS_HI (SHARED_BUFFER+0x020C) > +#define NGENE_EVENT (SHARED_BUFFER+0x0210) > +#define NGENE_EVENT_HI (SHARED_BUFFER+0x0214) > +#define VARIABLES (SHARED_BUFFER+0x0210) > + > +#define NGENE_INT_COUNTS (SHARED_BUFFER+0x0260) > +#define NGENE_INT_ENABLE (SHARED_BUFFER+0x0264) > +#define NGENE_VBI_LINE_COUNT (SHARED_BUFFER+0x0268) > + > +#define BUFFER_GP_XMIT (SHARED_BUFFER+0x0800) > +#define BUFFER_GP_RECV (SHARED_BUFFER+0x0900) > +#define EEPROM_AREA (SHARED_BUFFER+0x0A00) > + > +#define SG_V_IN_1 (SHARED_BUFFER+0x0A80) > +#define SG_VBI_1 (SHARED_BUFFER+0x0B00) > +#define SG_A_IN_1 (SHARED_BUFFER+0x0B80) > +#define SG_V_IN_2 (SHARED_BUFFER+0x0C00) > +#define SG_VBI_2 (SHARED_BUFFER+0x0C80) > +#define SG_A_IN_2 (SHARED_BUFFER+0x0D00) > +#define SG_V_OUT (SHARED_BUFFER+0x0D80) > +#define SG_A_OUT2 (SHARED_BUFFER+0x0E00) > + > +#define DATA_A_IN_1 (SHARED_BUFFER+0x0E80) > +#define DATA_A_IN_2 (SHARED_BUFFER+0x0F00) > +#define DATA_A_OUT (SHARED_BUFFER+0x0F80) > +#define DATA_V_IN_1 (SHARED_BUFFER+0x1000) > +#define DATA_V_IN_2 (SHARED_BUFFER+0x2000) > +#define DATA_V_OUT (SHARED_BUFFER+0x3000) > + > +#define DATA_FIFO_AREA (SHARED_BUFFER+0x1000) > + > +#define TIMESTAMPS 0xA000 > +#define SCRATCHPAD 0xA080 > +#define FORCE_INT 0xA088 > +#define FORCE_NMI 0xA090 > +#define INT_STATUS 0xA0A0 > + > +#define DEV_VER 0x9004 > + > +#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF) > + > +struct SG_ADDR { > + u64 start; > + u64 curr; > + u16 curr_ptr; > + u16 elements; > + u32 pad[3]; > +} __attribute__ ((__packed__)); > + > +struct SHARED_MEMORY { > + /* C000 */ > + u32 HostToNgene[64]; > + > + /* C100 */ > + u32 NgeneToHost[64]; > + > + /* C200 */ > + u64 NgeneCommand; > + u64 NgeneStatus; > + u64 NgeneEvent; > + > + /* C210 */ > + u8 pad1[0xc260 - 0xc218]; > + > + /* C260 */ > + u32 IntCounts; > + u32 IntEnable; > + > + /* C268 */ > + u8 pad2[0xd000 - 0xc268]; > + > +} __attribute__ ((__packed__)); > + > +struct BUFFER_STREAM_RESULTS { > + u32 Clock; /* Stream time in 100ns units */ > + u16 RemainingLines; /* Remaining lines in this field. > + 0 for complete field */ > + u8 FieldCount; /* Video field number */ > + u8 Flags; /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow, > + Bit 0 = FieldID */ > + u16 BlockCount; /* Audio block count (unused) */ > + u8 Reserved[2]; > + u32 DTOUpdate; > +} __attribute__ ((__packed__)); > + > +struct HW_SCATTER_GATHER_ELEMENT { > + u64 Address; > + u32 Length; > + u32 Reserved; > +} __attribute__ ((__packed__)); > + > +struct BUFFER_HEADER { > + u64 Next; > + struct BUFFER_STREAM_RESULTS SR; > + > + u32 Number_of_entries_1; > + u32 Reserved5; > + u64 Address_of_first_entry_1; > + > + u32 Number_of_entries_2; > + u32 Reserved7; > + u64 Address_of_first_entry_2; > +} __attribute__ ((__packed__)); > + > +struct EVENT_BUFFER { > + u32 TimeStamp; > + u8 GPIOStatus; > + u8 UARTStatus; > + u8 RXCharacter; > + u8 EventStatus; > + u32 Reserved[2]; > +} __attribute__ ((__packed__)); > + > +typedef struct EVENT_BUFFER *PEVENT_BUFFER; > + > +/* Firmware commands. */ > + > +enum OPCODES { > + CMD_NOP = 0, > + CMD_FWLOAD_PREPARE = 0x01, > + CMD_FWLOAD_FINISH = 0x02, > + CMD_I2C_READ = 0x03, > + CMD_I2C_WRITE = 0x04, > + > + CMD_I2C_WRITE_NOSTOP = 0x05, > + CMD_I2C_CONTINUE_WRITE = 0x06, > + CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07, > + > + CMD_DEBUG_OUTPUT = 0x09, > + > + CMD_CONTROL = 0x10, > + CMD_CONFIGURE_BUFFER = 0x11, > + CMD_CONFIGURE_FREE_BUFFER = 0x12, > + > + CMD_SPI_READ = 0x13, > + CMD_SPI_WRITE = 0x14, > + > + CMD_MEM_READ = 0x20, > + CMD_MEM_WRITE = 0x21, > + CMD_SFR_READ = 0x22, > + CMD_SFR_WRITE = 0x23, > + CMD_IRAM_READ = 0x24, > + CMD_IRAM_WRITE = 0x25, > + CMD_SET_GPIO_PIN = 0x26, > + CMD_SET_GPIO_INT = 0x27, > + CMD_CONFIGURE_UART = 0x28, > + CMD_WRITE_UART = 0x29, > + MAX_CMD > +}; > + > +enum RESPONSES { > + OK = 0, > + ERROR = 1 > +}; > + > +struct FW_HEADER { > + u8 Opcode; > + u8 Length; > +} __attribute__ ((__packed__)); > + > +struct FW_I2C_WRITE { > + struct FW_HEADER hdr; > + u8 Device; > + u8 Data[250]; > +} __attribute__ ((__packed__)); > + > +struct FW_I2C_CONTINUE_WRITE { > + struct FW_HEADER hdr; > + u8 Data[250]; > +} __attribute__ ((__packed__)); > + > +struct FW_I2C_READ { > + struct FW_HEADER hdr; > + u8 Device; > + u8 Data[252]; /* followed by two bytes of read data count */ > +} __attribute__ ((__packed__)); > + > +struct FW_SPI_WRITE { > + struct FW_HEADER hdr; > + u8 ModeSelect; > + u8 Data[250]; > +} __attribute__ ((__packed__)); > + > +struct FW_SPI_READ { > + struct FW_HEADER hdr; > + u8 ModeSelect; > + u8 Data[252]; /* followed by two bytes of read data count */ > +} __attribute__ ((__packed__)); > + > +struct FW_FWLOAD_PREPARE { > + struct FW_HEADER hdr; > +} __attribute__ ((__packed__)); > + > +struct FW_FWLOAD_FINISH { > + struct FW_HEADER hdr; > + u16 Address; /* address of final block */ > + u16 Length; > +} __attribute__ ((__packed__)); > + > +/* > + * Meaning of FW_STREAM_CONTROL::Mode bits: > + * Bit 7: Loopback PEXin to PEXout using TVOut channel > + * Bit 6: AVLOOP > + * Bit 5: Audio select; 0=I2S, 1=SPDIF > + * Bit 4: AVSYNC > + * Bit 3: Enable transport stream > + * Bit 2: Enable audio capture > + * Bit 1: Enable ITU-Video VBI capture > + * Bit 0: Enable ITU-Video capture > + * > + * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL) > + * Bit 7: continuous capture > + * Bit 6: capture one field > + * Bit 5: capture one frame > + * Bit 4: unused > + * Bit 3: starting field; 0=odd, 1=even > + * Bit 2: sample size; 0=8-bit, 1=10-bit > + * Bit 1: data format; 0=UYVY, 1=YUY2 > + * Bit 0: resets buffer pointers > +*/ > + > +enum FSC_MODE_BITS { > + SMODE_LOOPBACK = 0x80, > + SMODE_AVLOOP = 0x40, > + _SMODE_AUDIO_SPDIF = 0x20, > + _SMODE_AVSYNC = 0x10, > + _SMODE_TRANSPORT_STREAM = 0x08, > + _SMODE_AUDIO_CAPTURE = 0x04, > + _SMODE_VBI_CAPTURE = 0x02, > + _SMODE_VIDEO_CAPTURE = 0x01 > +}; > + > + > +/* Meaning of FW_STREAM_CONTROL::Stream bits: > + * Bit 3: Audio sample count: 0 = relative, 1 = absolute > + * Bit 2: color bar select; 1=color bars, 0=CV3 decoder > + * Bits 1-0: stream select, UVI1, UVI2, TVOUT > + */ > + > +struct FW_STREAM_CONTROL { > + struct FW_HEADER hdr; > + u8 Stream; /* Stream number (UVI1, UVI2, TVOUT) */ > + u8 Control; /* Value written to UVI1_CTL */ > + u8 Mode; /* Controls clock source */ > + u8 SetupDataLen; /* Length of setup data, MSB=1 write > + backwards */ > + u16 CaptureBlockCount; /* Blocks (a 256 Bytes) to capture per buffer > + for TS and Audio */ > + u64 Buffer_Address; /* Address of first buffer header */ > + u16 BytesPerVideoLine; > + u16 MaxLinesPerField; > + u16 MinLinesPerField; > + u16 Reserved_1; > + u16 BytesPerVBILine; > + u16 MaxVBILinesPerField; > + u16 MinVBILinesPerField; > + u16 SetupDataAddr; /* ngene relative address of setup data */ > + u8 SetupData[32]; /* setup data */ > +} __attribute__((__packed__)); > + > +#define AUDIO_BLOCK_SIZE 256 > +#define TS_BLOCK_SIZE 256 > + > +struct FW_MEM_READ { > + struct FW_HEADER hdr; > + u16 address; > +} __attribute__ ((__packed__)); > + > +struct FW_MEM_WRITE { > + struct FW_HEADER hdr; > + u16 address; > + u8 data; > +} __attribute__ ((__packed__)); > + > +struct FW_SFR_IRAM_READ { > + struct FW_HEADER hdr; > + u8 address; > +} __attribute__ ((__packed__)); > + > +struct FW_SFR_IRAM_WRITE { > + struct FW_HEADER hdr; > + u8 address; > + u8 data; > +} __attribute__ ((__packed__)); > + > +struct FW_SET_GPIO_PIN { > + struct FW_HEADER hdr; > + u8 select; > +} __attribute__ ((__packed__)); > + > +struct FW_SET_GPIO_INT { > + struct FW_HEADER hdr; > + u8 select; > +} __attribute__ ((__packed__)); > + > +struct FW_SET_DEBUGMODE { > + struct FW_HEADER hdr; > + u8 debug_flags; > +} __attribute__ ((__packed__)); > + > +struct FW_CONFIGURE_BUFFERS { > + struct FW_HEADER hdr; > + u8 config; > +} __attribute__ ((__packed__)); > + > +enum _BUFFER_CONFIGS { > + /* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2 (standard usage) */ > + BUFFER_CONFIG_4422 = 0, > + /* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2 (4x TS input usage) */ > + BUFFER_CONFIG_3333 = 1, > + /* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut (HDTV decoder usage) */ > + BUFFER_CONFIG_8022 = 2, > + BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */ > +}; > + > +struct FW_CONFIGURE_FREE_BUFFERS { > + struct FW_HEADER hdr; > + u8 UVI1_BufferLength; > + u8 UVI2_BufferLength; > + u8 TVO_BufferLength; > + u8 AUD1_BufferLength; > + u8 AUD2_BufferLength; > + u8 TVA_BufferLength; > +} __attribute__ ((__packed__)); > + > +struct FW_CONFIGURE_UART { > + struct FW_HEADER hdr; > + u8 UartControl; > +} __attribute__ ((__packed__)); > + > +enum _UART_CONFIG { > + _UART_BAUDRATE_19200 = 0, > + _UART_BAUDRATE_9600 = 1, > + _UART_BAUDRATE_4800 = 2, > + _UART_BAUDRATE_2400 = 3, > + _UART_RX_ENABLE = 0x40, > + _UART_TX_ENABLE = 0x80, > +}; > + > +struct FW_WRITE_UART { > + struct FW_HEADER hdr; > + u8 Data[252]; > +} __attribute__ ((__packed__)); > + > + > +struct ngene_command { > + u32 in_len; > + u32 out_len; > + union { > + u32 raw[64]; > + u8 raw8[256]; > + struct FW_HEADER hdr; > + struct FW_I2C_WRITE I2CWrite; > + struct FW_I2C_CONTINUE_WRITE I2CContinueWrite; > + struct FW_I2C_READ I2CRead; > + struct FW_STREAM_CONTROL StreamControl; > + struct FW_FWLOAD_PREPARE FWLoadPrepare; > + struct FW_FWLOAD_FINISH FWLoadFinish; > + struct FW_MEM_READ MemoryRead; > + struct FW_MEM_WRITE MemoryWrite; > + struct FW_SFR_IRAM_READ SfrIramRead; > + struct FW_SFR_IRAM_WRITE SfrIramWrite; > + struct FW_SPI_WRITE SPIWrite; > + struct FW_SPI_READ SPIRead; > + struct FW_SET_GPIO_PIN SetGpioPin; > + struct FW_SET_GPIO_INT SetGpioInt; > + struct FW_SET_DEBUGMODE SetDebugMode; > + struct FW_CONFIGURE_BUFFERS ConfigureBuffers; > + struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers; > + struct FW_CONFIGURE_UART ConfigureUart; > + struct FW_WRITE_UART WriteUart; > + } cmd; > +} __attribute__ ((__packed__)); > + > +#define NGENE_INTERFACE_VERSION 0x103 > +#define MAX_VIDEO_BUFFER_SIZE (417792) /* 288*1440 rounded up to next page */ > +#define MAX_AUDIO_BUFFER_SIZE (8192) /* Gives room for about 23msec@48KHz */ > +#define MAX_VBI_BUFFER_SIZE (28672) /* 1144*18 rounded up to next page */ > +#define MAX_TS_BUFFER_SIZE (98304) /* 512*188 rounded up to next page */ > +#define MAX_HDTV_BUFFER_SIZE (2080768) /* 541*1920*2 rounded up to next page > + Max: (1920x1080i60) */ > + > +#define OVERFLOW_BUFFER_SIZE (8192) > + > +#define RING_SIZE_VIDEO 4 > +#define RING_SIZE_AUDIO 8 > +#define RING_SIZE_TS 8 > + > +#define NUM_SCATTER_GATHER_ENTRIES 8 > + > +#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \ > + RING_SIZE_VIDEO * 2) + \ > + (MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \ > + (MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \ > + (RING_SIZE_VIDEO * PAGE_SIZE * 2) + \ > + (RING_SIZE_AUDIO * PAGE_SIZE * 2) + \ > + (RING_SIZE_TS * PAGE_SIZE * 4) + \ > + 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE) > + > +#define EVENT_QUEUE_SIZE 16 > + > +typedef struct HW_SCATTER_GATHER_ELEMENT *PHW_SCATTER_GATHER_ELEMENT; > +typedef struct FWRB *PFWRB; > + > +/* Gathers the current state of a single channel. */ > + > +struct SBufferHeader { > + struct BUFFER_HEADER ngeneBuffer; /* Physical descriptor */ > + struct SBufferHeader *Next; > + void *Buffer1; > + PHW_SCATTER_GATHER_ELEMENT scList1; > + void *Buffer2; > + PHW_SCATTER_GATHER_ELEMENT scList2; > +}; > + > +/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */ > +#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63) > + > +enum HWSTATE { > + HWSTATE_STOP, > + HWSTATE_STARTUP, > + HWSTATE_RUN, > + HWSTATE_PAUSE, > +}; > + > +enum KSSTATE { > + KSSTATE_STOP, > + KSSTATE_ACQUIRE, > + KSSTATE_PAUSE, > + KSSTATE_RUN, > +}; > + > +struct SRingBufferDescriptor { > + struct SBufferHeader *Head; /* Points to first buffer in ring buffer > + structure*/ > + u64 PAHead; /* Physical address of first buffer */ > + u32 MemSize; /* Memory size of allocated ring buffers > + (needed for freeing) */ > + u32 NumBuffers; /* Number of buffers in the ring */ > + u32 Buffer1Length; /* Allocated length of Buffer 1 */ > + u32 Buffer2Length; /* Allocated length of Buffer 2 */ > + void *SCListMem; /* Memory to hold scatter gather lists for this > + ring */ > + u64 PASCListMem; /* Physical address .. */ > + u32 SCListMemSize; /* Size of this memory */ > +}; > + > +enum STREAMMODEFLAGS { > + StreamMode_NONE = 0, /* Stream not used */ > + StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */ > + StreamMode_TSIN = 2, /* Transport stream input (all) */ > + StreamMode_HDTV = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60 > + (only stream 0) */ > + StreamMode_TSOUT = 8, /* Transport stream output (only stream 3) */ > +}; > + > + > +enum BufferExchangeFlags { > + BEF_EVEN_FIELD = 0x00000001, > + BEF_CONTINUATION = 0x00000002, > + BEF_MORE_DATA = 0x00000004, > + BEF_OVERFLOW = 0x00000008, > + DF_SWAP32 = 0x00010000, > +}; > + > +typedef void *(IBufferExchange)(void *, void *, u32, u32, u32); > + > +typedef struct { > + IBufferExchange *pExchange; > + IBufferExchange *pExchangeVBI; /* Secondary (VBI, ancillary) */ > + u8 Stream; > + u8 Flags; > + u8 Mode; > + u8 Reserved; > + u16 nLinesVideo; > + u16 nBytesPerLineVideo; > + u16 nLinesVBI; > + u16 nBytesPerLineVBI; > + u32 CaptureLength; /* Used for audio and transport stream */ > +} MICI_STREAMINFO, *PMICI_STREAMINFO; > + > +/****************************************************************************/ > +/* STRUCTS ******************************************************************/ > +/****************************************************************************/ > + > +/* sound hardware definition */ > +#define MIXER_ADDR_TVTUNER 0 > +#define MIXER_ADDR_LAST 0 > + > +struct ngene_channel; > + > +/*struct sound chip*/ > + > +struct mychip { > + struct ngene_channel *chan; > + struct snd_card *card; > + struct pci_dev *pci; > + struct snd_pcm_substream *substream; > + struct snd_pcm *pcm; > + unsigned long port; > + int irq; > + spinlock_t mixer_lock; > + spinlock_t lock; > + int mixer_volume[MIXER_ADDR_LAST + 1][2]; > + int capture_source[MIXER_ADDR_LAST + 1][2]; > +}; > + > +#ifdef NGENE_V4L > +struct ngene_overlay { > + int tvnorm; > + struct v4l2_rect w; > + enum v4l2_field field; > + struct v4l2_clip *clips; > + int nclips; > + int setup_ok; > +}; > + > +struct ngene_tvnorm { > + int v4l2_id; > + char *name; > + u16 swidth, sheight; /* scaled standard width, height */ > + int tuner_norm; > + int soundstd; > +}; > + > +struct ngene_vopen { > + struct ngene_channel *ch; > + enum v4l2_priority prio; > + int width; > + int height; > + int depth; > + struct videobuf_queue vbuf_q; > + struct videobuf_queue vbi; > + int fourcc; > + int picxcount; > + int resources; > + enum v4l2_buf_type type; > + const struct ngene_format *fmt; > + > + const struct ngene_format *ovfmt; > + struct ngene_overlay ov; > +}; > +#endif > + > +struct ngene_channel { > + struct device device; > + struct i2c_adapter i2c_adapter; > + > + struct ngene *dev; > + int number; > + int type; > + int mode; > + > + struct dvb_frontend *fe; > + struct dmxdev dmxdev; > + struct dvb_demux demux; > + struct dmx_frontend hw_frontend; > + struct dmx_frontend mem_frontend; > + int users; > + struct video_device *v4l_dev; > + struct tasklet_struct demux_tasklet; > + > + struct SBufferHeader *nextBuffer; > + enum KSSTATE State; > + enum HWSTATE HWState; > + u8 Stream; > + u8 Flags; > + u8 Mode; > + IBufferExchange *pBufferExchange; > + IBufferExchange *pBufferExchange2; > + > + spinlock_t state_lock; > + u16 nLines; > + u16 nBytesPerLine; > + u16 nVBILines; > + u16 nBytesPerVBILine; > + u16 itumode; > + u32 Capture1Length; > + u32 Capture2Length; > + struct SRingBufferDescriptor RingBuffer; > + struct SRingBufferDescriptor TSRingBuffer; > + struct SRingBufferDescriptor TSIdleBuffer; > + > + u32 DataFormatFlags; > + > + int AudioDTOUpdated; > + u32 AudioDTOValue; > + > + int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t); > + u8 lnbh; > + > + /* stuff from analog driver */ > + > + int minor; > + struct mychip *mychip; > + struct snd_card *soundcard; > + u8 *evenbuffer; > + u8 dma_on; > + int soundstreamon; > + int audiomute; > + int soundbuffisallocated; > + int sndbuffflag; > + int tun_rdy; > + int dec_rdy; > + int tun_dec_rdy; > + int lastbufferflag; > + > + struct ngene_tvnorm *tvnorms; > + int tvnorm_num; > + int tvnorm; > + > +#ifdef NGENE_V4L > + int videousers; > + struct v4l2_prio_state prio; > + struct ngene_vopen init; > + int resources; > + struct v4l2_framebuffer fbuf; > + struct ngene_buffer *screen; /* overlay */ > + struct list_head capture; /* video capture queue */ > + spinlock_t s_lock; > + struct semaphore reslock; > +#endif > + > + int running; > +}; > + > +struct ngene; > + > +typedef void (rx_cb_t)(struct ngene *, u32, u8); > +typedef void (tx_cb_t)(struct ngene *, u32); > + > +struct ngene { > + int nr; > + struct pci_dev *pci_dev; > + unsigned char *iomem; > + > + /*struct i2c_adapter i2c_adapter;*/ > + > + u32 device_version; > + u32 fw_interface_version; > + u32 icounts; > + > + u8 *CmdDoneByte; > + int BootFirmware; > + void *OverflowBuffer; > + dma_addr_t PAOverflowBuffer; > + void *FWInterfaceBuffer; > + dma_addr_t PAFWInterfaceBuffer; > + u8 *ngenetohost; > + u8 *hosttongene; > + > + struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; > + int EventQueueOverflowCount; > + int EventQueueOverflowFlag; > + struct tasklet_struct event_tasklet; > + struct EVENT_BUFFER *EventBuffer; > + int EventQueueWriteIndex; > + int EventQueueReadIndex; > + > + wait_queue_head_t cmd_wq; > + int cmd_done; > + struct semaphore cmd_mutex; > + struct semaphore stream_mutex; > + struct semaphore pll_mutex; > + struct semaphore i2c_switch_mutex; > + int i2c_current_channel; > + int i2c_current_bus; > + spinlock_t cmd_lock; > + > + struct dvb_adapter adapter[MAX_STREAM]; > + struct ngene_channel channel[MAX_STREAM]; > + > + struct ngene_info *card_info; > + > + tx_cb_t *TxEventNotify; > + rx_cb_t *RxEventNotify; > + int tx_busy; > + wait_queue_head_t tx_wq; > + wait_queue_head_t rx_wq; > +#define UART_RBUF_LEN 4096 > + u8 uart_rbuf[UART_RBUF_LEN]; > + int uart_rp, uart_wp; > + > + u8 *tsout_buf; > +#define TSOUT_BUF_SIZE (512*188*8) > + struct dvb_ringbuffer tsout_rbuf; > + > + u8 *ain_buf; > +#define AIN_BUF_SIZE (128*1024) > + struct dvb_ringbuffer ain_rbuf; > + > + > + u8 *vin_buf; > +#define VIN_BUF_SIZE (4*1920*1080) > + struct dvb_ringbuffer vin_rbuf; > + > + unsigned long exp_val; > + int prev_cmd; > +}; > + > +struct ngene_info { > + int type; > +#define NGENE_APP 0 > +#define NGENE_TERRATEC 1 > +#define NGENE_SIDEWINDER 2 > +#define NGENE_RACER 3 > +#define NGENE_VIPER 4 > +#define NGENE_PYTHON 5 > +#define NGENE_VBOX_V1 6 > +#define NGENE_VBOX_V2 7 > + > + int fw_version; > + char *name; > + > + int io_type[MAX_STREAM]; > +#define NGENE_IO_NONE 0 > +#define NGENE_IO_TV 1 > +#define NGENE_IO_HDTV 2 > +#define NGENE_IO_TSIN 4 > +#define NGENE_IO_TSOUT 8 > +#define NGENE_IO_AIN 16 > + > + void *fe_config[4]; > + void *tuner_config[4]; > + > + int (*demod_attach[4])(struct ngene_channel *); > + int (*tuner_attach[4])(struct ngene_channel *); > + > + u8 avf[4]; > + u8 msp[4]; > + u8 demoda[4]; > + u8 lnb[4]; > + int i2c_access; > + u8 ntsc; > + u8 tsf[4]; > + u8 i2s[4]; > + > + int (*gate_ctrl)(struct dvb_frontend *, int); > + int (*switch_ctrl)(struct ngene_channel *, int, int); > +}; > + > +#ifdef NGENE_V4L > +struct ngene_format{ > + char *name; > + int fourcc; /* video4linux 2 */ > + int btformat; /* BT848_COLOR_FMT_* */ > + int format; > + int btswap; /* BT848_COLOR_CTL_* */ > + int depth; /* bit/pixel */ > + int flags; > + int hshift, vshift; /* for planar modes */ > + int palette; > +}; > + > +#define RESOURCE_OVERLAY 1 > +#define RESOURCE_VIDEO 2 > +#define RESOURCE_VBI 4 > + > +struct ngene_buffer { > + /* common v4l buffer stuff -- must be first */ > + struct videobuf_buffer vb; > + > + /* ngene specific */ > + const struct ngene_format *fmt; > + int tvnorm; > + int btformat; > + int btswap; > +}; > +#endif > + > + > +#endif > + > +/* LocalWords: Endif > + */ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html