125aee3deSMauro Carvalho Chehab /* 225aee3deSMauro Carvalho Chehab * ngene.c: nGene PCIe bridge driver 325aee3deSMauro Carvalho Chehab * 425aee3deSMauro Carvalho Chehab * Copyright (C) 2005-2007 Micronas 525aee3deSMauro Carvalho Chehab * 625aee3deSMauro Carvalho Chehab * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de> 725aee3deSMauro Carvalho Chehab * Modifications for new nGene firmware, 825aee3deSMauro Carvalho Chehab * support for EEPROM-copying, 925aee3deSMauro Carvalho Chehab * support for new dual DVB-S2 card prototype 1025aee3deSMauro Carvalho Chehab * 1125aee3deSMauro Carvalho Chehab * 1225aee3deSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or 1325aee3deSMauro Carvalho Chehab * modify it under the terms of the GNU General Public License 1425aee3deSMauro Carvalho Chehab * version 2 only, as published by the Free Software Foundation. 1525aee3deSMauro Carvalho Chehab * 1625aee3deSMauro Carvalho Chehab * 1725aee3deSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 1825aee3deSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 1925aee3deSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2025aee3deSMauro Carvalho Chehab * GNU General Public License for more details. 2125aee3deSMauro Carvalho Chehab * 2225aee3deSMauro Carvalho Chehab * 2325aee3deSMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 2425aee3deSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 2525aee3deSMauro Carvalho Chehab * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2625aee3deSMauro Carvalho Chehab * 02110-1301, USA 2725aee3deSMauro Carvalho Chehab * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 2825aee3deSMauro Carvalho Chehab */ 2925aee3deSMauro Carvalho Chehab 3025aee3deSMauro Carvalho Chehab #include <linux/module.h> 3125aee3deSMauro Carvalho Chehab #include <linux/init.h> 3225aee3deSMauro Carvalho Chehab #include <linux/delay.h> 3325aee3deSMauro Carvalho Chehab #include <linux/poll.h> 3425aee3deSMauro Carvalho Chehab #include <linux/io.h> 3525aee3deSMauro Carvalho Chehab #include <asm/div64.h> 3625aee3deSMauro Carvalho Chehab #include <linux/pci.h> 3725aee3deSMauro Carvalho Chehab #include <linux/timer.h> 3825aee3deSMauro Carvalho Chehab #include <linux/byteorder/generic.h> 3925aee3deSMauro Carvalho Chehab #include <linux/firmware.h> 4025aee3deSMauro Carvalho Chehab #include <linux/vmalloc.h> 4125aee3deSMauro Carvalho Chehab 4225aee3deSMauro Carvalho Chehab #include "ngene.h" 4325aee3deSMauro Carvalho Chehab 4425aee3deSMauro Carvalho Chehab static int one_adapter; 4525aee3deSMauro Carvalho Chehab module_param(one_adapter, int, 0444); 4625aee3deSMauro Carvalho Chehab MODULE_PARM_DESC(one_adapter, "Use only one adapter."); 4725aee3deSMauro Carvalho Chehab 4825aee3deSMauro Carvalho Chehab static int shutdown_workaround; 4925aee3deSMauro Carvalho Chehab module_param(shutdown_workaround, int, 0644); 5025aee3deSMauro Carvalho Chehab MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets."); 5125aee3deSMauro Carvalho Chehab 5225aee3deSMauro Carvalho Chehab static int debug; 5325aee3deSMauro Carvalho Chehab module_param(debug, int, 0444); 5425aee3deSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Print debugging information."); 5525aee3deSMauro Carvalho Chehab 5625aee3deSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 5725aee3deSMauro Carvalho Chehab 5825aee3deSMauro Carvalho Chehab #define dprintk if (debug) printk 5925aee3deSMauro Carvalho Chehab 6025aee3deSMauro Carvalho Chehab #define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) 6125aee3deSMauro Carvalho Chehab #define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) 6225aee3deSMauro Carvalho Chehab #define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) 6325aee3deSMauro Carvalho Chehab #define ngreadl(adr) readl(dev->iomem + (adr)) 6425aee3deSMauro Carvalho Chehab #define ngreadb(adr) readb(dev->iomem + (adr)) 6525aee3deSMauro Carvalho Chehab #define ngcpyto(adr, src, count) memcpy_toio((char *) \ 6625aee3deSMauro Carvalho Chehab (dev->iomem + (adr)), (src), (count)) 6725aee3deSMauro Carvalho Chehab #define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ 6825aee3deSMauro Carvalho Chehab (dev->iomem + (adr)), (count)) 6925aee3deSMauro Carvalho Chehab 7025aee3deSMauro Carvalho Chehab /****************************************************************************/ 7125aee3deSMauro Carvalho Chehab /* nGene interrupt handler **************************************************/ 7225aee3deSMauro Carvalho Chehab /****************************************************************************/ 7325aee3deSMauro Carvalho Chehab 7425aee3deSMauro Carvalho Chehab static void event_tasklet(unsigned long data) 7525aee3deSMauro Carvalho Chehab { 7625aee3deSMauro Carvalho Chehab struct ngene *dev = (struct ngene *)data; 7725aee3deSMauro Carvalho Chehab 7825aee3deSMauro Carvalho Chehab while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { 7925aee3deSMauro Carvalho Chehab struct EVENT_BUFFER Event = 8025aee3deSMauro Carvalho Chehab dev->EventQueue[dev->EventQueueReadIndex]; 8125aee3deSMauro Carvalho Chehab dev->EventQueueReadIndex = 8225aee3deSMauro Carvalho Chehab (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1); 8325aee3deSMauro Carvalho Chehab 8425aee3deSMauro Carvalho Chehab if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify)) 8525aee3deSMauro Carvalho Chehab dev->TxEventNotify(dev, Event.TimeStamp); 8625aee3deSMauro Carvalho Chehab if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify)) 8725aee3deSMauro Carvalho Chehab dev->RxEventNotify(dev, Event.TimeStamp, 8825aee3deSMauro Carvalho Chehab Event.RXCharacter); 8925aee3deSMauro Carvalho Chehab } 9025aee3deSMauro Carvalho Chehab } 9125aee3deSMauro Carvalho Chehab 9225aee3deSMauro Carvalho Chehab static void demux_tasklet(unsigned long data) 9325aee3deSMauro Carvalho Chehab { 9425aee3deSMauro Carvalho Chehab struct ngene_channel *chan = (struct ngene_channel *)data; 9525aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = chan->nextBuffer; 9625aee3deSMauro Carvalho Chehab 9725aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock); 9825aee3deSMauro Carvalho Chehab 9925aee3deSMauro Carvalho Chehab while (Cur->ngeneBuffer.SR.Flags & 0x80) { 10025aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) { 10125aee3deSMauro Carvalho Chehab u32 Flags = chan->DataFormatFlags; 10225aee3deSMauro Carvalho Chehab if (Cur->ngeneBuffer.SR.Flags & 0x20) 10325aee3deSMauro Carvalho Chehab Flags |= BEF_OVERFLOW; 10425aee3deSMauro Carvalho Chehab if (chan->pBufferExchange) { 10525aee3deSMauro Carvalho Chehab if (!chan->pBufferExchange(chan, 10625aee3deSMauro Carvalho Chehab Cur->Buffer1, 10725aee3deSMauro Carvalho Chehab chan->Capture1Length, 10825aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR. 10925aee3deSMauro Carvalho Chehab Clock, Flags)) { 11025aee3deSMauro Carvalho Chehab /* 11125aee3deSMauro Carvalho Chehab We didn't get data 11225aee3deSMauro Carvalho Chehab Clear in service flag to make sure we 11325aee3deSMauro Carvalho Chehab get called on next interrupt again. 11425aee3deSMauro Carvalho Chehab leave fill/empty (0x80) flag alone 11525aee3deSMauro Carvalho Chehab to avoid hardware running out of 11625aee3deSMauro Carvalho Chehab buffers during startup, we hold only 11725aee3deSMauro Carvalho Chehab in run state ( the source may be late 11825aee3deSMauro Carvalho Chehab delivering data ) 11925aee3deSMauro Carvalho Chehab */ 12025aee3deSMauro Carvalho Chehab 12125aee3deSMauro Carvalho Chehab if (chan->HWState == HWSTATE_RUN) { 12225aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Flags &= 12325aee3deSMauro Carvalho Chehab ~0x40; 12425aee3deSMauro Carvalho Chehab break; 12525aee3deSMauro Carvalho Chehab /* Stop processing stream */ 12625aee3deSMauro Carvalho Chehab } 12725aee3deSMauro Carvalho Chehab } else { 12825aee3deSMauro Carvalho Chehab /* We got a valid buffer, 12925aee3deSMauro Carvalho Chehab so switch to run state */ 13025aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_RUN; 13125aee3deSMauro Carvalho Chehab } 13225aee3deSMauro Carvalho Chehab } else { 13325aee3deSMauro Carvalho Chehab printk(KERN_ERR DEVICE_NAME ": OOPS\n"); 13425aee3deSMauro Carvalho Chehab if (chan->HWState == HWSTATE_RUN) { 13525aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Flags &= ~0x40; 13625aee3deSMauro Carvalho Chehab break; /* Stop processing stream */ 13725aee3deSMauro Carvalho Chehab } 13825aee3deSMauro Carvalho Chehab } 13925aee3deSMauro Carvalho Chehab if (chan->AudioDTOUpdated) { 14025aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME 14125aee3deSMauro Carvalho Chehab ": Update AudioDTO = %d\n", 14225aee3deSMauro Carvalho Chehab chan->AudioDTOValue); 14325aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.DTOUpdate = 14425aee3deSMauro Carvalho Chehab chan->AudioDTOValue; 14525aee3deSMauro Carvalho Chehab chan->AudioDTOUpdated = 0; 14625aee3deSMauro Carvalho Chehab } 14725aee3deSMauro Carvalho Chehab } else { 14825aee3deSMauro Carvalho Chehab if (chan->HWState == HWSTATE_RUN) { 14925aee3deSMauro Carvalho Chehab u32 Flags = chan->DataFormatFlags; 15025aee3deSMauro Carvalho Chehab IBufferExchange *exch1 = chan->pBufferExchange; 15125aee3deSMauro Carvalho Chehab IBufferExchange *exch2 = chan->pBufferExchange2; 15225aee3deSMauro Carvalho Chehab if (Cur->ngeneBuffer.SR.Flags & 0x01) 15325aee3deSMauro Carvalho Chehab Flags |= BEF_EVEN_FIELD; 15425aee3deSMauro Carvalho Chehab if (Cur->ngeneBuffer.SR.Flags & 0x20) 15525aee3deSMauro Carvalho Chehab Flags |= BEF_OVERFLOW; 15625aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock); 15725aee3deSMauro Carvalho Chehab if (exch1) 15825aee3deSMauro Carvalho Chehab exch1(chan, Cur->Buffer1, 15925aee3deSMauro Carvalho Chehab chan->Capture1Length, 16025aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Clock, 16125aee3deSMauro Carvalho Chehab Flags); 16225aee3deSMauro Carvalho Chehab if (exch2) 16325aee3deSMauro Carvalho Chehab exch2(chan, Cur->Buffer2, 16425aee3deSMauro Carvalho Chehab chan->Capture2Length, 16525aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Clock, 16625aee3deSMauro Carvalho Chehab Flags); 16725aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock); 16825aee3deSMauro Carvalho Chehab } else if (chan->HWState != HWSTATE_STOP) 16925aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_RUN; 17025aee3deSMauro Carvalho Chehab } 17125aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Flags = 0x00; 17225aee3deSMauro Carvalho Chehab Cur = Cur->Next; 17325aee3deSMauro Carvalho Chehab } 17425aee3deSMauro Carvalho Chehab chan->nextBuffer = Cur; 17525aee3deSMauro Carvalho Chehab 17625aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock); 17725aee3deSMauro Carvalho Chehab } 17825aee3deSMauro Carvalho Chehab 17925aee3deSMauro Carvalho Chehab static irqreturn_t irq_handler(int irq, void *dev_id) 18025aee3deSMauro Carvalho Chehab { 18125aee3deSMauro Carvalho Chehab struct ngene *dev = (struct ngene *)dev_id; 18225aee3deSMauro Carvalho Chehab u32 icounts = 0; 18325aee3deSMauro Carvalho Chehab irqreturn_t rc = IRQ_NONE; 18425aee3deSMauro Carvalho Chehab u32 i = MAX_STREAM; 18525aee3deSMauro Carvalho Chehab u8 *tmpCmdDoneByte; 18625aee3deSMauro Carvalho Chehab 18725aee3deSMauro Carvalho Chehab if (dev->BootFirmware) { 18825aee3deSMauro Carvalho Chehab icounts = ngreadl(NGENE_INT_COUNTS); 18925aee3deSMauro Carvalho Chehab if (icounts != dev->icounts) { 19025aee3deSMauro Carvalho Chehab ngwritel(0, FORCE_NMI); 19125aee3deSMauro Carvalho Chehab dev->cmd_done = 1; 19225aee3deSMauro Carvalho Chehab wake_up(&dev->cmd_wq); 19325aee3deSMauro Carvalho Chehab dev->icounts = icounts; 19425aee3deSMauro Carvalho Chehab rc = IRQ_HANDLED; 19525aee3deSMauro Carvalho Chehab } 19625aee3deSMauro Carvalho Chehab return rc; 19725aee3deSMauro Carvalho Chehab } 19825aee3deSMauro Carvalho Chehab 19925aee3deSMauro Carvalho Chehab ngwritel(0, FORCE_NMI); 20025aee3deSMauro Carvalho Chehab 20125aee3deSMauro Carvalho Chehab spin_lock(&dev->cmd_lock); 20225aee3deSMauro Carvalho Chehab tmpCmdDoneByte = dev->CmdDoneByte; 20325aee3deSMauro Carvalho Chehab if (tmpCmdDoneByte && 20425aee3deSMauro Carvalho Chehab (*tmpCmdDoneByte || 20525aee3deSMauro Carvalho Chehab (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) { 20625aee3deSMauro Carvalho Chehab dev->CmdDoneByte = NULL; 20725aee3deSMauro Carvalho Chehab dev->cmd_done = 1; 20825aee3deSMauro Carvalho Chehab wake_up(&dev->cmd_wq); 20925aee3deSMauro Carvalho Chehab rc = IRQ_HANDLED; 21025aee3deSMauro Carvalho Chehab } 21125aee3deSMauro Carvalho Chehab spin_unlock(&dev->cmd_lock); 21225aee3deSMauro Carvalho Chehab 21325aee3deSMauro Carvalho Chehab if (dev->EventBuffer->EventStatus & 0x80) { 21425aee3deSMauro Carvalho Chehab u8 nextWriteIndex = 21525aee3deSMauro Carvalho Chehab (dev->EventQueueWriteIndex + 1) & 21625aee3deSMauro Carvalho Chehab (EVENT_QUEUE_SIZE - 1); 21725aee3deSMauro Carvalho Chehab if (nextWriteIndex != dev->EventQueueReadIndex) { 21825aee3deSMauro Carvalho Chehab dev->EventQueue[dev->EventQueueWriteIndex] = 21925aee3deSMauro Carvalho Chehab *(dev->EventBuffer); 22025aee3deSMauro Carvalho Chehab dev->EventQueueWriteIndex = nextWriteIndex; 22125aee3deSMauro Carvalho Chehab } else { 22225aee3deSMauro Carvalho Chehab printk(KERN_ERR DEVICE_NAME ": event overflow\n"); 22325aee3deSMauro Carvalho Chehab dev->EventQueueOverflowCount += 1; 22425aee3deSMauro Carvalho Chehab dev->EventQueueOverflowFlag = 1; 22525aee3deSMauro Carvalho Chehab } 22625aee3deSMauro Carvalho Chehab dev->EventBuffer->EventStatus &= ~0x80; 22725aee3deSMauro Carvalho Chehab tasklet_schedule(&dev->event_tasklet); 22825aee3deSMauro Carvalho Chehab rc = IRQ_HANDLED; 22925aee3deSMauro Carvalho Chehab } 23025aee3deSMauro Carvalho Chehab 23125aee3deSMauro Carvalho Chehab while (i > 0) { 23225aee3deSMauro Carvalho Chehab i--; 23325aee3deSMauro Carvalho Chehab spin_lock(&dev->channel[i].state_lock); 23425aee3deSMauro Carvalho Chehab /* if (dev->channel[i].State>=KSSTATE_RUN) { */ 23525aee3deSMauro Carvalho Chehab if (dev->channel[i].nextBuffer) { 23625aee3deSMauro Carvalho Chehab if ((dev->channel[i].nextBuffer-> 23725aee3deSMauro Carvalho Chehab ngeneBuffer.SR.Flags & 0xC0) == 0x80) { 23825aee3deSMauro Carvalho Chehab dev->channel[i].nextBuffer-> 23925aee3deSMauro Carvalho Chehab ngeneBuffer.SR.Flags |= 0x40; 24025aee3deSMauro Carvalho Chehab tasklet_schedule( 24125aee3deSMauro Carvalho Chehab &dev->channel[i].demux_tasklet); 24225aee3deSMauro Carvalho Chehab rc = IRQ_HANDLED; 24325aee3deSMauro Carvalho Chehab } 24425aee3deSMauro Carvalho Chehab } 24525aee3deSMauro Carvalho Chehab spin_unlock(&dev->channel[i].state_lock); 24625aee3deSMauro Carvalho Chehab } 24725aee3deSMauro Carvalho Chehab 24825aee3deSMauro Carvalho Chehab /* Request might have been processed by a previous call. */ 24925aee3deSMauro Carvalho Chehab return IRQ_HANDLED; 25025aee3deSMauro Carvalho Chehab } 25125aee3deSMauro Carvalho Chehab 25225aee3deSMauro Carvalho Chehab /****************************************************************************/ 25325aee3deSMauro Carvalho Chehab /* nGene command interface **************************************************/ 25425aee3deSMauro Carvalho Chehab /****************************************************************************/ 25525aee3deSMauro Carvalho Chehab 25625aee3deSMauro Carvalho Chehab static void dump_command_io(struct ngene *dev) 25725aee3deSMauro Carvalho Chehab { 25825aee3deSMauro Carvalho Chehab u8 buf[8], *b; 25925aee3deSMauro Carvalho Chehab 26025aee3deSMauro Carvalho Chehab ngcpyfrom(buf, HOST_TO_NGENE, 8); 26125aee3deSMauro Carvalho Chehab printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf); 26225aee3deSMauro Carvalho Chehab 26325aee3deSMauro Carvalho Chehab ngcpyfrom(buf, NGENE_TO_HOST, 8); 26425aee3deSMauro Carvalho Chehab printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf); 26525aee3deSMauro Carvalho Chehab 26625aee3deSMauro Carvalho Chehab b = dev->hosttongene; 26725aee3deSMauro Carvalho Chehab printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b); 26825aee3deSMauro Carvalho Chehab 26925aee3deSMauro Carvalho Chehab b = dev->ngenetohost; 27025aee3deSMauro Carvalho Chehab printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b); 27125aee3deSMauro Carvalho Chehab } 27225aee3deSMauro Carvalho Chehab 27325aee3deSMauro Carvalho Chehab static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) 27425aee3deSMauro Carvalho Chehab { 27525aee3deSMauro Carvalho Chehab int ret; 27625aee3deSMauro Carvalho Chehab u8 *tmpCmdDoneByte; 27725aee3deSMauro Carvalho Chehab 27825aee3deSMauro Carvalho Chehab dev->cmd_done = 0; 27925aee3deSMauro Carvalho Chehab 28025aee3deSMauro Carvalho Chehab if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) { 28125aee3deSMauro Carvalho Chehab dev->BootFirmware = 1; 28225aee3deSMauro Carvalho Chehab dev->icounts = ngreadl(NGENE_INT_COUNTS); 28325aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_COMMAND); 28425aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_COMMAND_HI); 28525aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_STATUS); 28625aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_STATUS_HI); 28725aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_EVENT); 28825aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_EVENT_HI); 28925aee3deSMauro Carvalho Chehab } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) { 29025aee3deSMauro Carvalho Chehab u64 fwio = dev->PAFWInterfaceBuffer; 29125aee3deSMauro Carvalho Chehab 29225aee3deSMauro Carvalho Chehab ngwritel(fwio & 0xffffffff, NGENE_COMMAND); 29325aee3deSMauro Carvalho Chehab ngwritel(fwio >> 32, NGENE_COMMAND_HI); 29425aee3deSMauro Carvalho Chehab ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS); 29525aee3deSMauro Carvalho Chehab ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI); 29625aee3deSMauro Carvalho Chehab ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT); 29725aee3deSMauro Carvalho Chehab ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI); 29825aee3deSMauro Carvalho Chehab } 29925aee3deSMauro Carvalho Chehab 30025aee3deSMauro Carvalho Chehab memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2); 30125aee3deSMauro Carvalho Chehab 30225aee3deSMauro Carvalho Chehab if (dev->BootFirmware) 30325aee3deSMauro Carvalho Chehab ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2); 30425aee3deSMauro Carvalho Chehab 30525aee3deSMauro Carvalho Chehab spin_lock_irq(&dev->cmd_lock); 30625aee3deSMauro Carvalho Chehab tmpCmdDoneByte = dev->ngenetohost + com->out_len; 30725aee3deSMauro Carvalho Chehab if (!com->out_len) 30825aee3deSMauro Carvalho Chehab tmpCmdDoneByte++; 30925aee3deSMauro Carvalho Chehab *tmpCmdDoneByte = 0; 31025aee3deSMauro Carvalho Chehab dev->ngenetohost[0] = 0; 31125aee3deSMauro Carvalho Chehab dev->ngenetohost[1] = 0; 31225aee3deSMauro Carvalho Chehab dev->CmdDoneByte = tmpCmdDoneByte; 31325aee3deSMauro Carvalho Chehab spin_unlock_irq(&dev->cmd_lock); 31425aee3deSMauro Carvalho Chehab 31525aee3deSMauro Carvalho Chehab /* Notify 8051. */ 31625aee3deSMauro Carvalho Chehab ngwritel(1, FORCE_INT); 31725aee3deSMauro Carvalho Chehab 31825aee3deSMauro Carvalho Chehab ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ); 31925aee3deSMauro Carvalho Chehab if (!ret) { 32025aee3deSMauro Carvalho Chehab /*ngwritel(0, FORCE_NMI);*/ 32125aee3deSMauro Carvalho Chehab 32225aee3deSMauro Carvalho Chehab printk(KERN_ERR DEVICE_NAME 32325aee3deSMauro Carvalho Chehab ": Command timeout cmd=%02x prev=%02x\n", 32425aee3deSMauro Carvalho Chehab com->cmd.hdr.Opcode, dev->prev_cmd); 32525aee3deSMauro Carvalho Chehab dump_command_io(dev); 32625aee3deSMauro Carvalho Chehab return -1; 32725aee3deSMauro Carvalho Chehab } 32825aee3deSMauro Carvalho Chehab if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) 32925aee3deSMauro Carvalho Chehab dev->BootFirmware = 0; 33025aee3deSMauro Carvalho Chehab 33125aee3deSMauro Carvalho Chehab dev->prev_cmd = com->cmd.hdr.Opcode; 33225aee3deSMauro Carvalho Chehab 33325aee3deSMauro Carvalho Chehab if (!com->out_len) 33425aee3deSMauro Carvalho Chehab return 0; 33525aee3deSMauro Carvalho Chehab 33625aee3deSMauro Carvalho Chehab memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len); 33725aee3deSMauro Carvalho Chehab 33825aee3deSMauro Carvalho Chehab return 0; 33925aee3deSMauro Carvalho Chehab } 34025aee3deSMauro Carvalho Chehab 34125aee3deSMauro Carvalho Chehab int ngene_command(struct ngene *dev, struct ngene_command *com) 34225aee3deSMauro Carvalho Chehab { 34325aee3deSMauro Carvalho Chehab int result; 34425aee3deSMauro Carvalho Chehab 34525aee3deSMauro Carvalho Chehab down(&dev->cmd_mutex); 34625aee3deSMauro Carvalho Chehab result = ngene_command_mutex(dev, com); 34725aee3deSMauro Carvalho Chehab up(&dev->cmd_mutex); 34825aee3deSMauro Carvalho Chehab return result; 34925aee3deSMauro Carvalho Chehab } 35025aee3deSMauro Carvalho Chehab 35125aee3deSMauro Carvalho Chehab 35225aee3deSMauro Carvalho Chehab static int ngene_command_load_firmware(struct ngene *dev, 35325aee3deSMauro Carvalho Chehab u8 *ngene_fw, u32 size) 35425aee3deSMauro Carvalho Chehab { 35525aee3deSMauro Carvalho Chehab #define FIRSTCHUNK (1024) 35625aee3deSMauro Carvalho Chehab u32 cleft; 35725aee3deSMauro Carvalho Chehab struct ngene_command com; 35825aee3deSMauro Carvalho Chehab 35925aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE; 36025aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 0; 36125aee3deSMauro Carvalho Chehab com.in_len = 0; 36225aee3deSMauro Carvalho Chehab com.out_len = 0; 36325aee3deSMauro Carvalho Chehab 36425aee3deSMauro Carvalho Chehab ngene_command(dev, &com); 36525aee3deSMauro Carvalho Chehab 36625aee3deSMauro Carvalho Chehab cleft = (size + 3) & ~3; 36725aee3deSMauro Carvalho Chehab if (cleft > FIRSTCHUNK) { 36825aee3deSMauro Carvalho Chehab ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK, 36925aee3deSMauro Carvalho Chehab cleft - FIRSTCHUNK); 37025aee3deSMauro Carvalho Chehab cleft = FIRSTCHUNK; 37125aee3deSMauro Carvalho Chehab } 37225aee3deSMauro Carvalho Chehab ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft); 37325aee3deSMauro Carvalho Chehab 37425aee3deSMauro Carvalho Chehab memset(&com, 0, sizeof(struct ngene_command)); 37525aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH; 37625aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 4; 37725aee3deSMauro Carvalho Chehab com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA; 37825aee3deSMauro Carvalho Chehab com.cmd.FWLoadFinish.Length = (unsigned short)cleft; 37925aee3deSMauro Carvalho Chehab com.in_len = 4; 38025aee3deSMauro Carvalho Chehab com.out_len = 0; 38125aee3deSMauro Carvalho Chehab 38225aee3deSMauro Carvalho Chehab return ngene_command(dev, &com); 38325aee3deSMauro Carvalho Chehab } 38425aee3deSMauro Carvalho Chehab 38525aee3deSMauro Carvalho Chehab 38625aee3deSMauro Carvalho Chehab static int ngene_command_config_buf(struct ngene *dev, u8 config) 38725aee3deSMauro Carvalho Chehab { 38825aee3deSMauro Carvalho Chehab struct ngene_command com; 38925aee3deSMauro Carvalho Chehab 39025aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER; 39125aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 1; 39225aee3deSMauro Carvalho Chehab com.cmd.ConfigureBuffers.config = config; 39325aee3deSMauro Carvalho Chehab com.in_len = 1; 39425aee3deSMauro Carvalho Chehab com.out_len = 0; 39525aee3deSMauro Carvalho Chehab 39625aee3deSMauro Carvalho Chehab if (ngene_command(dev, &com) < 0) 39725aee3deSMauro Carvalho Chehab return -EIO; 39825aee3deSMauro Carvalho Chehab return 0; 39925aee3deSMauro Carvalho Chehab } 40025aee3deSMauro Carvalho Chehab 40125aee3deSMauro Carvalho Chehab static int ngene_command_config_free_buf(struct ngene *dev, u8 *config) 40225aee3deSMauro Carvalho Chehab { 40325aee3deSMauro Carvalho Chehab struct ngene_command com; 40425aee3deSMauro Carvalho Chehab 40525aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER; 40625aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 6; 40725aee3deSMauro Carvalho Chehab memcpy(&com.cmd.ConfigureBuffers.config, config, 6); 40825aee3deSMauro Carvalho Chehab com.in_len = 6; 40925aee3deSMauro Carvalho Chehab com.out_len = 0; 41025aee3deSMauro Carvalho Chehab 41125aee3deSMauro Carvalho Chehab if (ngene_command(dev, &com) < 0) 41225aee3deSMauro Carvalho Chehab return -EIO; 41325aee3deSMauro Carvalho Chehab 41425aee3deSMauro Carvalho Chehab return 0; 41525aee3deSMauro Carvalho Chehab } 41625aee3deSMauro Carvalho Chehab 41725aee3deSMauro Carvalho Chehab int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level) 41825aee3deSMauro Carvalho Chehab { 41925aee3deSMauro Carvalho Chehab struct ngene_command com; 42025aee3deSMauro Carvalho Chehab 42125aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN; 42225aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 1; 42325aee3deSMauro Carvalho Chehab com.cmd.SetGpioPin.select = select | (level << 7); 42425aee3deSMauro Carvalho Chehab com.in_len = 1; 42525aee3deSMauro Carvalho Chehab com.out_len = 0; 42625aee3deSMauro Carvalho Chehab 42725aee3deSMauro Carvalho Chehab return ngene_command(dev, &com); 42825aee3deSMauro Carvalho Chehab } 42925aee3deSMauro Carvalho Chehab 43025aee3deSMauro Carvalho Chehab 43125aee3deSMauro Carvalho Chehab /* 43225aee3deSMauro Carvalho Chehab 02000640 is sample on rising edge. 43325aee3deSMauro Carvalho Chehab 02000740 is sample on falling edge. 43425aee3deSMauro Carvalho Chehab 02000040 is ignore "valid" signal 43525aee3deSMauro Carvalho Chehab 43625aee3deSMauro Carvalho Chehab 0: FD_CTL1 Bit 7,6 must be 0,1 43725aee3deSMauro Carvalho Chehab 7 disable(fw controlled) 43825aee3deSMauro Carvalho Chehab 6 0-AUX,1-TS 43925aee3deSMauro Carvalho Chehab 5 0-par,1-ser 44025aee3deSMauro Carvalho Chehab 4 0-lsb/1-msb 44125aee3deSMauro Carvalho Chehab 3,2 reserved 44225aee3deSMauro Carvalho Chehab 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both 44325aee3deSMauro Carvalho Chehab 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge 44425aee3deSMauro Carvalho Chehab 2: FD_STA is read-only. 0-sync 44525aee3deSMauro Carvalho Chehab 3: FD_INSYNC is number of 47s to trigger "in sync". 44625aee3deSMauro Carvalho Chehab 4: FD_OUTSYNC is number of 47s to trigger "out of sync". 44725aee3deSMauro Carvalho Chehab 5: FD_MAXBYTE1 is low-order of bytes per packet. 44825aee3deSMauro Carvalho Chehab 6: FD_MAXBYTE2 is high-order of bytes per packet. 44925aee3deSMauro Carvalho Chehab 7: Top byte is unused. 45025aee3deSMauro Carvalho Chehab */ 45125aee3deSMauro Carvalho Chehab 45225aee3deSMauro Carvalho Chehab /****************************************************************************/ 45325aee3deSMauro Carvalho Chehab 45425aee3deSMauro Carvalho Chehab static u8 TSFeatureDecoderSetup[8 * 5] = { 45525aee3deSMauro Carvalho Chehab 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, 45625aee3deSMauro Carvalho Chehab 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ 45725aee3deSMauro Carvalho Chehab 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ 45825aee3deSMauro Carvalho Chehab 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ 45925aee3deSMauro Carvalho Chehab 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ 46025aee3deSMauro Carvalho Chehab }; 46125aee3deSMauro Carvalho Chehab 46225aee3deSMauro Carvalho Chehab /* Set NGENE I2S Config to 16 bit packed */ 46325aee3deSMauro Carvalho Chehab static u8 I2SConfiguration[] = { 46425aee3deSMauro Carvalho Chehab 0x00, 0x10, 0x00, 0x00, 46525aee3deSMauro Carvalho Chehab 0x80, 0x10, 0x00, 0x00, 46625aee3deSMauro Carvalho Chehab }; 46725aee3deSMauro Carvalho Chehab 46825aee3deSMauro Carvalho Chehab static u8 SPDIFConfiguration[10] = { 46925aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 47025aee3deSMauro Carvalho Chehab }; 47125aee3deSMauro Carvalho Chehab 47225aee3deSMauro Carvalho Chehab /* Set NGENE I2S Config to transport stream compatible mode */ 47325aee3deSMauro Carvalho Chehab 47425aee3deSMauro Carvalho Chehab static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 }; 47525aee3deSMauro Carvalho Chehab 47625aee3deSMauro Carvalho Chehab static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 }; 47725aee3deSMauro Carvalho Chehab 47825aee3deSMauro Carvalho Chehab static u8 ITUDecoderSetup[4][16] = { 47925aee3deSMauro Carvalho Chehab {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */ 48025aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00}, 48125aee3deSMauro Carvalho Chehab {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, 48225aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, 48325aee3deSMauro Carvalho Chehab {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */ 48425aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, 48525aee3deSMauro Carvalho Chehab {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */ 48625aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, 48725aee3deSMauro Carvalho Chehab }; 48825aee3deSMauro Carvalho Chehab 48925aee3deSMauro Carvalho Chehab /* 49025aee3deSMauro Carvalho Chehab * 50 48 60 gleich 49125aee3deSMauro Carvalho Chehab * 27p50 9f 00 22 80 42 69 18 ... 49225aee3deSMauro Carvalho Chehab * 27p60 93 00 22 80 82 69 1c ... 49325aee3deSMauro Carvalho Chehab */ 49425aee3deSMauro Carvalho Chehab 49525aee3deSMauro Carvalho Chehab /* Maxbyte to 1144 (for raw data) */ 49625aee3deSMauro Carvalho Chehab static u8 ITUFeatureDecoderSetup[8] = { 49725aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00 49825aee3deSMauro Carvalho Chehab }; 49925aee3deSMauro Carvalho Chehab 50025aee3deSMauro Carvalho Chehab void FillTSBuffer(void *Buffer, int Length, u32 Flags) 50125aee3deSMauro Carvalho Chehab { 50225aee3deSMauro Carvalho Chehab u32 *ptr = Buffer; 50325aee3deSMauro Carvalho Chehab 50425aee3deSMauro Carvalho Chehab memset(Buffer, TS_FILLER, Length); 50525aee3deSMauro Carvalho Chehab while (Length > 0) { 50625aee3deSMauro Carvalho Chehab if (Flags & DF_SWAP32) 50725aee3deSMauro Carvalho Chehab *ptr = 0x471FFF10; 50825aee3deSMauro Carvalho Chehab else 50925aee3deSMauro Carvalho Chehab *ptr = 0x10FF1F47; 51025aee3deSMauro Carvalho Chehab ptr += (188 / 4); 51125aee3deSMauro Carvalho Chehab Length -= 188; 51225aee3deSMauro Carvalho Chehab } 51325aee3deSMauro Carvalho Chehab } 51425aee3deSMauro Carvalho Chehab 51525aee3deSMauro Carvalho Chehab 51625aee3deSMauro Carvalho Chehab static void flush_buffers(struct ngene_channel *chan) 51725aee3deSMauro Carvalho Chehab { 51825aee3deSMauro Carvalho Chehab u8 val; 51925aee3deSMauro Carvalho Chehab 52025aee3deSMauro Carvalho Chehab do { 52125aee3deSMauro Carvalho Chehab msleep(1); 52225aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock); 52325aee3deSMauro Carvalho Chehab val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80; 52425aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock); 52525aee3deSMauro Carvalho Chehab } while (val); 52625aee3deSMauro Carvalho Chehab } 52725aee3deSMauro Carvalho Chehab 52825aee3deSMauro Carvalho Chehab static void clear_buffers(struct ngene_channel *chan) 52925aee3deSMauro Carvalho Chehab { 53025aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = chan->nextBuffer; 53125aee3deSMauro Carvalho Chehab 53225aee3deSMauro Carvalho Chehab do { 53325aee3deSMauro Carvalho Chehab memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR)); 53425aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) 53525aee3deSMauro Carvalho Chehab FillTSBuffer(Cur->Buffer1, 53625aee3deSMauro Carvalho Chehab chan->Capture1Length, 53725aee3deSMauro Carvalho Chehab chan->DataFormatFlags); 53825aee3deSMauro Carvalho Chehab Cur = Cur->Next; 53925aee3deSMauro Carvalho Chehab } while (Cur != chan->nextBuffer); 54025aee3deSMauro Carvalho Chehab 54125aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) { 54225aee3deSMauro Carvalho Chehab chan->nextBuffer->ngeneBuffer.SR.DTOUpdate = 54325aee3deSMauro Carvalho Chehab chan->AudioDTOValue; 54425aee3deSMauro Carvalho Chehab chan->AudioDTOUpdated = 0; 54525aee3deSMauro Carvalho Chehab 54625aee3deSMauro Carvalho Chehab Cur = chan->TSIdleBuffer.Head; 54725aee3deSMauro Carvalho Chehab 54825aee3deSMauro Carvalho Chehab do { 54925aee3deSMauro Carvalho Chehab memset(&Cur->ngeneBuffer.SR, 0, 55025aee3deSMauro Carvalho Chehab sizeof(Cur->ngeneBuffer.SR)); 55125aee3deSMauro Carvalho Chehab FillTSBuffer(Cur->Buffer1, 55225aee3deSMauro Carvalho Chehab chan->Capture1Length, 55325aee3deSMauro Carvalho Chehab chan->DataFormatFlags); 55425aee3deSMauro Carvalho Chehab Cur = Cur->Next; 55525aee3deSMauro Carvalho Chehab } while (Cur != chan->TSIdleBuffer.Head); 55625aee3deSMauro Carvalho Chehab } 55725aee3deSMauro Carvalho Chehab } 55825aee3deSMauro Carvalho Chehab 55925aee3deSMauro Carvalho Chehab static int ngene_command_stream_control(struct ngene *dev, u8 stream, 56025aee3deSMauro Carvalho Chehab u8 control, u8 mode, u8 flags) 56125aee3deSMauro Carvalho Chehab { 56225aee3deSMauro Carvalho Chehab struct ngene_channel *chan = &dev->channel[stream]; 56325aee3deSMauro Carvalho Chehab struct ngene_command com; 56425aee3deSMauro Carvalho Chehab u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); 56525aee3deSMauro Carvalho Chehab u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500); 56625aee3deSMauro Carvalho Chehab u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); 56725aee3deSMauro Carvalho Chehab u16 BsSDO = 0x9B00; 56825aee3deSMauro Carvalho Chehab 56925aee3deSMauro Carvalho Chehab down(&dev->stream_mutex); 57025aee3deSMauro Carvalho Chehab memset(&com, 0, sizeof(com)); 57125aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_CONTROL; 57225aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; 57325aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream = stream | (control ? 8 : 0); 57425aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) 57525aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream |= 0x07; 57625aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Control = control | 57725aee3deSMauro Carvalho Chehab (flags & SFLAG_ORDER_LUMA_CHROMA); 57825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Mode = mode; 57925aee3deSMauro Carvalho Chehab com.in_len = sizeof(struct FW_STREAM_CONTROL); 58025aee3deSMauro Carvalho Chehab com.out_len = 0; 58125aee3deSMauro Carvalho Chehab 58225aee3deSMauro Carvalho Chehab dprintk(KERN_INFO DEVICE_NAME 58325aee3deSMauro Carvalho Chehab ": Stream=%02x, Control=%02x, Mode=%02x\n", 58425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, 58525aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Mode); 58625aee3deSMauro Carvalho Chehab 58725aee3deSMauro Carvalho Chehab chan->Mode = mode; 58825aee3deSMauro Carvalho Chehab 58925aee3deSMauro Carvalho Chehab if (!(control & 0x80)) { 59025aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock); 59125aee3deSMauro Carvalho Chehab if (chan->State == KSSTATE_RUN) { 59225aee3deSMauro Carvalho Chehab chan->State = KSSTATE_ACQUIRE; 59325aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_STOP; 59425aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock); 59525aee3deSMauro Carvalho Chehab if (ngene_command(dev, &com) < 0) { 59625aee3deSMauro Carvalho Chehab up(&dev->stream_mutex); 59725aee3deSMauro Carvalho Chehab return -1; 59825aee3deSMauro Carvalho Chehab } 59925aee3deSMauro Carvalho Chehab /* clear_buffers(chan); */ 60025aee3deSMauro Carvalho Chehab flush_buffers(chan); 60125aee3deSMauro Carvalho Chehab up(&dev->stream_mutex); 60225aee3deSMauro Carvalho Chehab return 0; 60325aee3deSMauro Carvalho Chehab } 60425aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock); 60525aee3deSMauro Carvalho Chehab up(&dev->stream_mutex); 60625aee3deSMauro Carvalho Chehab return 0; 60725aee3deSMauro Carvalho Chehab } 60825aee3deSMauro Carvalho Chehab 60925aee3deSMauro Carvalho Chehab if (mode & SMODE_AUDIO_CAPTURE) { 61025aee3deSMauro Carvalho Chehab com.cmd.StreamControl.CaptureBlockCount = 61125aee3deSMauro Carvalho Chehab chan->Capture1Length / AUDIO_BLOCK_SIZE; 61225aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; 61325aee3deSMauro Carvalho Chehab } else if (mode & SMODE_TRANSPORT_STREAM) { 61425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.CaptureBlockCount = 61525aee3deSMauro Carvalho Chehab chan->Capture1Length / TS_BLOCK_SIZE; 61625aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MaxLinesPerField = 61725aee3deSMauro Carvalho Chehab chan->Capture1Length / TS_BLOCK_SIZE; 61825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Buffer_Address = 61925aee3deSMauro Carvalho Chehab chan->TSRingBuffer.PAHead; 62025aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) { 62125aee3deSMauro Carvalho Chehab com.cmd.StreamControl.BytesPerVBILine = 62225aee3deSMauro Carvalho Chehab chan->Capture1Length / TS_BLOCK_SIZE; 62325aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream |= 0x07; 62425aee3deSMauro Carvalho Chehab } 62525aee3deSMauro Carvalho Chehab } else { 62625aee3deSMauro Carvalho Chehab com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine; 62725aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MaxLinesPerField = chan->nLines; 62825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MinLinesPerField = 100; 62925aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; 63025aee3deSMauro Carvalho Chehab 63125aee3deSMauro Carvalho Chehab if (mode & SMODE_VBI_CAPTURE) { 63225aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MaxVBILinesPerField = 63325aee3deSMauro Carvalho Chehab chan->nVBILines; 63425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MinVBILinesPerField = 0; 63525aee3deSMauro Carvalho Chehab com.cmd.StreamControl.BytesPerVBILine = 63625aee3deSMauro Carvalho Chehab chan->nBytesPerVBILine; 63725aee3deSMauro Carvalho Chehab } 63825aee3deSMauro Carvalho Chehab if (flags & SFLAG_COLORBAR) 63925aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream |= 0x04; 64025aee3deSMauro Carvalho Chehab } 64125aee3deSMauro Carvalho Chehab 64225aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock); 64325aee3deSMauro Carvalho Chehab if (mode & SMODE_AUDIO_CAPTURE) { 64425aee3deSMauro Carvalho Chehab chan->nextBuffer = chan->RingBuffer.Head; 64525aee3deSMauro Carvalho Chehab if (mode & SMODE_AUDIO_SPDIF) { 64625aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen = 64725aee3deSMauro Carvalho Chehab sizeof(SPDIFConfiguration); 64825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsSPI; 64925aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData, 65025aee3deSMauro Carvalho Chehab SPDIFConfiguration, sizeof(SPDIFConfiguration)); 65125aee3deSMauro Carvalho Chehab } else { 65225aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen = 4; 65325aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsSDI; 65425aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData, 65525aee3deSMauro Carvalho Chehab I2SConfiguration + 65625aee3deSMauro Carvalho Chehab 4 * dev->card_info->i2s[stream], 4); 65725aee3deSMauro Carvalho Chehab } 65825aee3deSMauro Carvalho Chehab } else if (mode & SMODE_TRANSPORT_STREAM) { 65925aee3deSMauro Carvalho Chehab chan->nextBuffer = chan->TSRingBuffer.Head; 66025aee3deSMauro Carvalho Chehab if (stream >= STREAM_AUDIOIN1) { 66125aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) { 66225aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen = 66325aee3deSMauro Carvalho Chehab sizeof(TS_I2SOutConfiguration); 66425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsSDO; 66525aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData, 66625aee3deSMauro Carvalho Chehab TS_I2SOutConfiguration, 66725aee3deSMauro Carvalho Chehab sizeof(TS_I2SOutConfiguration)); 66825aee3deSMauro Carvalho Chehab } else { 66925aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen = 67025aee3deSMauro Carvalho Chehab sizeof(TS_I2SConfiguration); 67125aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsSDI; 67225aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData, 67325aee3deSMauro Carvalho Chehab TS_I2SConfiguration, 67425aee3deSMauro Carvalho Chehab sizeof(TS_I2SConfiguration)); 67525aee3deSMauro Carvalho Chehab } 67625aee3deSMauro Carvalho Chehab } else { 67725aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen = 8; 67825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10; 67925aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData, 68025aee3deSMauro Carvalho Chehab TSFeatureDecoderSetup + 68125aee3deSMauro Carvalho Chehab 8 * dev->card_info->tsf[stream], 8); 68225aee3deSMauro Carvalho Chehab } 68325aee3deSMauro Carvalho Chehab } else { 68425aee3deSMauro Carvalho Chehab chan->nextBuffer = chan->RingBuffer.Head; 68525aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen = 68625aee3deSMauro Carvalho Chehab 16 + sizeof(ITUFeatureDecoderSetup); 68725aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsUVI; 68825aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData, 68925aee3deSMauro Carvalho Chehab ITUDecoderSetup[chan->itumode], 16); 69025aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData + 16, 69125aee3deSMauro Carvalho Chehab ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup)); 69225aee3deSMauro Carvalho Chehab } 69325aee3deSMauro Carvalho Chehab clear_buffers(chan); 69425aee3deSMauro Carvalho Chehab chan->State = KSSTATE_RUN; 69525aee3deSMauro Carvalho Chehab if (mode & SMODE_TRANSPORT_STREAM) 69625aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_RUN; 69725aee3deSMauro Carvalho Chehab else 69825aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_STARTUP; 69925aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock); 70025aee3deSMauro Carvalho Chehab 70125aee3deSMauro Carvalho Chehab if (ngene_command(dev, &com) < 0) { 70225aee3deSMauro Carvalho Chehab up(&dev->stream_mutex); 70325aee3deSMauro Carvalho Chehab return -1; 70425aee3deSMauro Carvalho Chehab } 70525aee3deSMauro Carvalho Chehab up(&dev->stream_mutex); 70625aee3deSMauro Carvalho Chehab return 0; 70725aee3deSMauro Carvalho Chehab } 70825aee3deSMauro Carvalho Chehab 70925aee3deSMauro Carvalho Chehab void set_transfer(struct ngene_channel *chan, int state) 71025aee3deSMauro Carvalho Chehab { 71125aee3deSMauro Carvalho Chehab u8 control = 0, mode = 0, flags = 0; 71225aee3deSMauro Carvalho Chehab struct ngene *dev = chan->dev; 71325aee3deSMauro Carvalho Chehab int ret; 71425aee3deSMauro Carvalho Chehab 71525aee3deSMauro Carvalho Chehab /* 71625aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME ": st %d\n", state); 71725aee3deSMauro Carvalho Chehab msleep(100); 71825aee3deSMauro Carvalho Chehab */ 71925aee3deSMauro Carvalho Chehab 72025aee3deSMauro Carvalho Chehab if (state) { 72125aee3deSMauro Carvalho Chehab if (chan->running) { 72225aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME ": already running\n"); 72325aee3deSMauro Carvalho Chehab return; 72425aee3deSMauro Carvalho Chehab } 72525aee3deSMauro Carvalho Chehab } else { 72625aee3deSMauro Carvalho Chehab if (!chan->running) { 72725aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME ": already stopped\n"); 72825aee3deSMauro Carvalho Chehab return; 72925aee3deSMauro Carvalho Chehab } 73025aee3deSMauro Carvalho Chehab } 73125aee3deSMauro Carvalho Chehab 73225aee3deSMauro Carvalho Chehab if (dev->card_info->switch_ctrl) 73325aee3deSMauro Carvalho Chehab dev->card_info->switch_ctrl(chan, 1, state ^ 1); 73425aee3deSMauro Carvalho Chehab 73525aee3deSMauro Carvalho Chehab if (state) { 73625aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock); 73725aee3deSMauro Carvalho Chehab 73825aee3deSMauro Carvalho Chehab /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", 73925aee3deSMauro Carvalho Chehab ngreadl(0x9310)); */ 74025aee3deSMauro Carvalho Chehab dvb_ringbuffer_flush(&dev->tsout_rbuf); 74125aee3deSMauro Carvalho Chehab control = 0x80; 74225aee3deSMauro Carvalho Chehab if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { 74325aee3deSMauro Carvalho Chehab chan->Capture1Length = 512 * 188; 74425aee3deSMauro Carvalho Chehab mode = SMODE_TRANSPORT_STREAM; 74525aee3deSMauro Carvalho Chehab } 74625aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) { 74725aee3deSMauro Carvalho Chehab chan->pBufferExchange = tsout_exchange; 74825aee3deSMauro Carvalho Chehab /* 0x66666666 = 50MHz *2^33 /250MHz */ 74925aee3deSMauro Carvalho Chehab chan->AudioDTOValue = 0x80000000; 75025aee3deSMauro Carvalho Chehab chan->AudioDTOUpdated = 1; 75125aee3deSMauro Carvalho Chehab } 75225aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSIN) 75325aee3deSMauro Carvalho Chehab chan->pBufferExchange = tsin_exchange; 75425aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock); 7552827a440SMauro Carvalho Chehab } 7562827a440SMauro Carvalho Chehab /* else printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", 75725aee3deSMauro Carvalho Chehab ngreadl(0x9310)); */ 75825aee3deSMauro Carvalho Chehab 75925aee3deSMauro Carvalho Chehab ret = ngene_command_stream_control(dev, chan->number, 76025aee3deSMauro Carvalho Chehab control, mode, flags); 76125aee3deSMauro Carvalho Chehab if (!ret) 76225aee3deSMauro Carvalho Chehab chan->running = state; 76325aee3deSMauro Carvalho Chehab else 76425aee3deSMauro Carvalho Chehab printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", 76525aee3deSMauro Carvalho Chehab state); 76625aee3deSMauro Carvalho Chehab if (!state) { 76725aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock); 76825aee3deSMauro Carvalho Chehab chan->pBufferExchange = NULL; 76925aee3deSMauro Carvalho Chehab dvb_ringbuffer_flush(&dev->tsout_rbuf); 77025aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock); 77125aee3deSMauro Carvalho Chehab } 77225aee3deSMauro Carvalho Chehab } 77325aee3deSMauro Carvalho Chehab 77425aee3deSMauro Carvalho Chehab 77525aee3deSMauro Carvalho Chehab /****************************************************************************/ 77625aee3deSMauro Carvalho Chehab /* nGene hardware init and release functions ********************************/ 77725aee3deSMauro Carvalho Chehab /****************************************************************************/ 77825aee3deSMauro Carvalho Chehab 77925aee3deSMauro Carvalho Chehab static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb) 78025aee3deSMauro Carvalho Chehab { 78125aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = rb->Head; 78225aee3deSMauro Carvalho Chehab u32 j; 78325aee3deSMauro Carvalho Chehab 78425aee3deSMauro Carvalho Chehab if (!Cur) 78525aee3deSMauro Carvalho Chehab return; 78625aee3deSMauro Carvalho Chehab 78725aee3deSMauro Carvalho Chehab for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) { 78825aee3deSMauro Carvalho Chehab if (Cur->Buffer1) 78925aee3deSMauro Carvalho Chehab pci_free_consistent(dev->pci_dev, 79025aee3deSMauro Carvalho Chehab rb->Buffer1Length, 79125aee3deSMauro Carvalho Chehab Cur->Buffer1, 79225aee3deSMauro Carvalho Chehab Cur->scList1->Address); 79325aee3deSMauro Carvalho Chehab 79425aee3deSMauro Carvalho Chehab if (Cur->Buffer2) 79525aee3deSMauro Carvalho Chehab pci_free_consistent(dev->pci_dev, 79625aee3deSMauro Carvalho Chehab rb->Buffer2Length, 79725aee3deSMauro Carvalho Chehab Cur->Buffer2, 79825aee3deSMauro Carvalho Chehab Cur->scList2->Address); 79925aee3deSMauro Carvalho Chehab } 80025aee3deSMauro Carvalho Chehab 80125aee3deSMauro Carvalho Chehab if (rb->SCListMem) 80225aee3deSMauro Carvalho Chehab pci_free_consistent(dev->pci_dev, rb->SCListMemSize, 80325aee3deSMauro Carvalho Chehab rb->SCListMem, rb->PASCListMem); 80425aee3deSMauro Carvalho Chehab 80525aee3deSMauro Carvalho Chehab pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead); 80625aee3deSMauro Carvalho Chehab } 80725aee3deSMauro Carvalho Chehab 80825aee3deSMauro Carvalho Chehab static void free_idlebuffer(struct ngene *dev, 80925aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *rb, 81025aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *tb) 81125aee3deSMauro Carvalho Chehab { 81225aee3deSMauro Carvalho Chehab int j; 81325aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = tb->Head; 81425aee3deSMauro Carvalho Chehab 81525aee3deSMauro Carvalho Chehab if (!rb->Head) 81625aee3deSMauro Carvalho Chehab return; 81725aee3deSMauro Carvalho Chehab free_ringbuffer(dev, rb); 81825aee3deSMauro Carvalho Chehab for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) { 81925aee3deSMauro Carvalho Chehab Cur->Buffer2 = NULL; 82025aee3deSMauro Carvalho Chehab Cur->scList2 = NULL; 82125aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Address_of_first_entry_2 = 0; 82225aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Number_of_entries_2 = 0; 82325aee3deSMauro Carvalho Chehab } 82425aee3deSMauro Carvalho Chehab } 82525aee3deSMauro Carvalho Chehab 82625aee3deSMauro Carvalho Chehab static void free_common_buffers(struct ngene *dev) 82725aee3deSMauro Carvalho Chehab { 82825aee3deSMauro Carvalho Chehab u32 i; 82925aee3deSMauro Carvalho Chehab struct ngene_channel *chan; 83025aee3deSMauro Carvalho Chehab 83125aee3deSMauro Carvalho Chehab for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { 83225aee3deSMauro Carvalho Chehab chan = &dev->channel[i]; 83325aee3deSMauro Carvalho Chehab free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer); 83425aee3deSMauro Carvalho Chehab free_ringbuffer(dev, &chan->RingBuffer); 83525aee3deSMauro Carvalho Chehab free_ringbuffer(dev, &chan->TSRingBuffer); 83625aee3deSMauro Carvalho Chehab } 83725aee3deSMauro Carvalho Chehab 83825aee3deSMauro Carvalho Chehab if (dev->OverflowBuffer) 83925aee3deSMauro Carvalho Chehab pci_free_consistent(dev->pci_dev, 84025aee3deSMauro Carvalho Chehab OVERFLOW_BUFFER_SIZE, 84125aee3deSMauro Carvalho Chehab dev->OverflowBuffer, dev->PAOverflowBuffer); 84225aee3deSMauro Carvalho Chehab 84325aee3deSMauro Carvalho Chehab if (dev->FWInterfaceBuffer) 84425aee3deSMauro Carvalho Chehab pci_free_consistent(dev->pci_dev, 84525aee3deSMauro Carvalho Chehab 4096, 84625aee3deSMauro Carvalho Chehab dev->FWInterfaceBuffer, 84725aee3deSMauro Carvalho Chehab dev->PAFWInterfaceBuffer); 84825aee3deSMauro Carvalho Chehab } 84925aee3deSMauro Carvalho Chehab 85025aee3deSMauro Carvalho Chehab /****************************************************************************/ 85125aee3deSMauro Carvalho Chehab /* Ring buffer handling *****************************************************/ 85225aee3deSMauro Carvalho Chehab /****************************************************************************/ 85325aee3deSMauro Carvalho Chehab 85425aee3deSMauro Carvalho Chehab static int create_ring_buffer(struct pci_dev *pci_dev, 85525aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *descr, u32 NumBuffers) 85625aee3deSMauro Carvalho Chehab { 85725aee3deSMauro Carvalho Chehab dma_addr_t tmp; 85825aee3deSMauro Carvalho Chehab struct SBufferHeader *Head; 85925aee3deSMauro Carvalho Chehab u32 i; 86025aee3deSMauro Carvalho Chehab u32 MemSize = SIZEOF_SBufferHeader * NumBuffers; 86125aee3deSMauro Carvalho Chehab u64 PARingBufferHead; 86225aee3deSMauro Carvalho Chehab u64 PARingBufferCur; 86325aee3deSMauro Carvalho Chehab u64 PARingBufferNext; 86425aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur, *Next; 86525aee3deSMauro Carvalho Chehab 86625aee3deSMauro Carvalho Chehab descr->Head = NULL; 86725aee3deSMauro Carvalho Chehab descr->MemSize = 0; 86825aee3deSMauro Carvalho Chehab descr->PAHead = 0; 86925aee3deSMauro Carvalho Chehab descr->NumBuffers = 0; 87025aee3deSMauro Carvalho Chehab 87125aee3deSMauro Carvalho Chehab if (MemSize < 4096) 87225aee3deSMauro Carvalho Chehab MemSize = 4096; 87325aee3deSMauro Carvalho Chehab 87425aee3deSMauro Carvalho Chehab Head = pci_alloc_consistent(pci_dev, MemSize, &tmp); 87525aee3deSMauro Carvalho Chehab PARingBufferHead = tmp; 87625aee3deSMauro Carvalho Chehab 87725aee3deSMauro Carvalho Chehab if (!Head) 87825aee3deSMauro Carvalho Chehab return -ENOMEM; 87925aee3deSMauro Carvalho Chehab 88025aee3deSMauro Carvalho Chehab memset(Head, 0, MemSize); 88125aee3deSMauro Carvalho Chehab 88225aee3deSMauro Carvalho Chehab PARingBufferCur = PARingBufferHead; 88325aee3deSMauro Carvalho Chehab Cur = Head; 88425aee3deSMauro Carvalho Chehab 88525aee3deSMauro Carvalho Chehab for (i = 0; i < NumBuffers - 1; i++) { 88625aee3deSMauro Carvalho Chehab Next = (struct SBufferHeader *) 88725aee3deSMauro Carvalho Chehab (((u8 *) Cur) + SIZEOF_SBufferHeader); 88825aee3deSMauro Carvalho Chehab PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader; 88925aee3deSMauro Carvalho Chehab Cur->Next = Next; 89025aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Next = PARingBufferNext; 89125aee3deSMauro Carvalho Chehab Cur = Next; 89225aee3deSMauro Carvalho Chehab PARingBufferCur = PARingBufferNext; 89325aee3deSMauro Carvalho Chehab } 89425aee3deSMauro Carvalho Chehab /* Last Buffer points back to first one */ 89525aee3deSMauro Carvalho Chehab Cur->Next = Head; 89625aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Next = PARingBufferHead; 89725aee3deSMauro Carvalho Chehab 89825aee3deSMauro Carvalho Chehab descr->Head = Head; 89925aee3deSMauro Carvalho Chehab descr->MemSize = MemSize; 90025aee3deSMauro Carvalho Chehab descr->PAHead = PARingBufferHead; 90125aee3deSMauro Carvalho Chehab descr->NumBuffers = NumBuffers; 90225aee3deSMauro Carvalho Chehab 90325aee3deSMauro Carvalho Chehab return 0; 90425aee3deSMauro Carvalho Chehab } 90525aee3deSMauro Carvalho Chehab 90625aee3deSMauro Carvalho Chehab static int AllocateRingBuffers(struct pci_dev *pci_dev, 90725aee3deSMauro Carvalho Chehab dma_addr_t of, 90825aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *pRingBuffer, 90925aee3deSMauro Carvalho Chehab u32 Buffer1Length, u32 Buffer2Length) 91025aee3deSMauro Carvalho Chehab { 91125aee3deSMauro Carvalho Chehab dma_addr_t tmp; 91225aee3deSMauro Carvalho Chehab u32 i, j; 91325aee3deSMauro Carvalho Chehab int status = 0; 91425aee3deSMauro Carvalho Chehab u32 SCListMemSize = pRingBuffer->NumBuffers 91525aee3deSMauro Carvalho Chehab * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) : 91625aee3deSMauro Carvalho Chehab NUM_SCATTER_GATHER_ENTRIES) 91725aee3deSMauro Carvalho Chehab * sizeof(struct HW_SCATTER_GATHER_ELEMENT); 91825aee3deSMauro Carvalho Chehab 91925aee3deSMauro Carvalho Chehab u64 PASCListMem; 92025aee3deSMauro Carvalho Chehab struct HW_SCATTER_GATHER_ELEMENT *SCListEntry; 92125aee3deSMauro Carvalho Chehab u64 PASCListEntry; 92225aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur; 92325aee3deSMauro Carvalho Chehab void *SCListMem; 92425aee3deSMauro Carvalho Chehab 92525aee3deSMauro Carvalho Chehab if (SCListMemSize < 4096) 92625aee3deSMauro Carvalho Chehab SCListMemSize = 4096; 92725aee3deSMauro Carvalho Chehab 92825aee3deSMauro Carvalho Chehab SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp); 92925aee3deSMauro Carvalho Chehab 93025aee3deSMauro Carvalho Chehab PASCListMem = tmp; 93125aee3deSMauro Carvalho Chehab if (SCListMem == NULL) 93225aee3deSMauro Carvalho Chehab return -ENOMEM; 93325aee3deSMauro Carvalho Chehab 93425aee3deSMauro Carvalho Chehab memset(SCListMem, 0, SCListMemSize); 93525aee3deSMauro Carvalho Chehab 93625aee3deSMauro Carvalho Chehab pRingBuffer->SCListMem = SCListMem; 93725aee3deSMauro Carvalho Chehab pRingBuffer->PASCListMem = PASCListMem; 93825aee3deSMauro Carvalho Chehab pRingBuffer->SCListMemSize = SCListMemSize; 93925aee3deSMauro Carvalho Chehab pRingBuffer->Buffer1Length = Buffer1Length; 94025aee3deSMauro Carvalho Chehab pRingBuffer->Buffer2Length = Buffer2Length; 94125aee3deSMauro Carvalho Chehab 94225aee3deSMauro Carvalho Chehab SCListEntry = SCListMem; 94325aee3deSMauro Carvalho Chehab PASCListEntry = PASCListMem; 94425aee3deSMauro Carvalho Chehab Cur = pRingBuffer->Head; 94525aee3deSMauro Carvalho Chehab 94625aee3deSMauro Carvalho Chehab for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) { 94725aee3deSMauro Carvalho Chehab u64 PABuffer; 94825aee3deSMauro Carvalho Chehab 94925aee3deSMauro Carvalho Chehab void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length, 95025aee3deSMauro Carvalho Chehab &tmp); 95125aee3deSMauro Carvalho Chehab PABuffer = tmp; 95225aee3deSMauro Carvalho Chehab 95325aee3deSMauro Carvalho Chehab if (Buffer == NULL) 95425aee3deSMauro Carvalho Chehab return -ENOMEM; 95525aee3deSMauro Carvalho Chehab 95625aee3deSMauro Carvalho Chehab Cur->Buffer1 = Buffer; 95725aee3deSMauro Carvalho Chehab 95825aee3deSMauro Carvalho Chehab SCListEntry->Address = PABuffer; 95925aee3deSMauro Carvalho Chehab SCListEntry->Length = Buffer1Length; 96025aee3deSMauro Carvalho Chehab 96125aee3deSMauro Carvalho Chehab Cur->scList1 = SCListEntry; 96225aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry; 96325aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Number_of_entries_1 = 96425aee3deSMauro Carvalho Chehab NUM_SCATTER_GATHER_ENTRIES; 96525aee3deSMauro Carvalho Chehab 96625aee3deSMauro Carvalho Chehab SCListEntry += 1; 96725aee3deSMauro Carvalho Chehab PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); 96825aee3deSMauro Carvalho Chehab 96925aee3deSMauro Carvalho Chehab #if NUM_SCATTER_GATHER_ENTRIES > 1 97025aee3deSMauro Carvalho Chehab for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) { 97125aee3deSMauro Carvalho Chehab SCListEntry->Address = of; 97225aee3deSMauro Carvalho Chehab SCListEntry->Length = OVERFLOW_BUFFER_SIZE; 97325aee3deSMauro Carvalho Chehab SCListEntry += 1; 97425aee3deSMauro Carvalho Chehab PASCListEntry += 97525aee3deSMauro Carvalho Chehab sizeof(struct HW_SCATTER_GATHER_ELEMENT); 97625aee3deSMauro Carvalho Chehab } 97725aee3deSMauro Carvalho Chehab #endif 97825aee3deSMauro Carvalho Chehab 97925aee3deSMauro Carvalho Chehab if (!Buffer2Length) 98025aee3deSMauro Carvalho Chehab continue; 98125aee3deSMauro Carvalho Chehab 98225aee3deSMauro Carvalho Chehab Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp); 98325aee3deSMauro Carvalho Chehab PABuffer = tmp; 98425aee3deSMauro Carvalho Chehab 98525aee3deSMauro Carvalho Chehab if (Buffer == NULL) 98625aee3deSMauro Carvalho Chehab return -ENOMEM; 98725aee3deSMauro Carvalho Chehab 98825aee3deSMauro Carvalho Chehab Cur->Buffer2 = Buffer; 98925aee3deSMauro Carvalho Chehab 99025aee3deSMauro Carvalho Chehab SCListEntry->Address = PABuffer; 99125aee3deSMauro Carvalho Chehab SCListEntry->Length = Buffer2Length; 99225aee3deSMauro Carvalho Chehab 99325aee3deSMauro Carvalho Chehab Cur->scList2 = SCListEntry; 99425aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry; 99525aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Number_of_entries_2 = 99625aee3deSMauro Carvalho Chehab NUM_SCATTER_GATHER_ENTRIES; 99725aee3deSMauro Carvalho Chehab 99825aee3deSMauro Carvalho Chehab SCListEntry += 1; 99925aee3deSMauro Carvalho Chehab PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); 100025aee3deSMauro Carvalho Chehab 100125aee3deSMauro Carvalho Chehab #if NUM_SCATTER_GATHER_ENTRIES > 1 100225aee3deSMauro Carvalho Chehab for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) { 100325aee3deSMauro Carvalho Chehab SCListEntry->Address = of; 100425aee3deSMauro Carvalho Chehab SCListEntry->Length = OVERFLOW_BUFFER_SIZE; 100525aee3deSMauro Carvalho Chehab SCListEntry += 1; 100625aee3deSMauro Carvalho Chehab PASCListEntry += 100725aee3deSMauro Carvalho Chehab sizeof(struct HW_SCATTER_GATHER_ELEMENT); 100825aee3deSMauro Carvalho Chehab } 100925aee3deSMauro Carvalho Chehab #endif 101025aee3deSMauro Carvalho Chehab 101125aee3deSMauro Carvalho Chehab } 101225aee3deSMauro Carvalho Chehab 101325aee3deSMauro Carvalho Chehab return status; 101425aee3deSMauro Carvalho Chehab } 101525aee3deSMauro Carvalho Chehab 101625aee3deSMauro Carvalho Chehab static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer, 101725aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *pRingBuffer) 101825aee3deSMauro Carvalho Chehab { 101925aee3deSMauro Carvalho Chehab int status = 0; 102025aee3deSMauro Carvalho Chehab 102125aee3deSMauro Carvalho Chehab /* Copy pointer to scatter gather list in TSRingbuffer 102225aee3deSMauro Carvalho Chehab structure for buffer 2 102325aee3deSMauro Carvalho Chehab Load number of buffer 102425aee3deSMauro Carvalho Chehab */ 102525aee3deSMauro Carvalho Chehab u32 n = pRingBuffer->NumBuffers; 102625aee3deSMauro Carvalho Chehab 102725aee3deSMauro Carvalho Chehab /* Point to first buffer entry */ 102825aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = pRingBuffer->Head; 102925aee3deSMauro Carvalho Chehab int i; 103025aee3deSMauro Carvalho Chehab /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */ 103125aee3deSMauro Carvalho Chehab for (i = 0; i < n; i++) { 103225aee3deSMauro Carvalho Chehab Cur->Buffer2 = pIdleBuffer->Head->Buffer1; 103325aee3deSMauro Carvalho Chehab Cur->scList2 = pIdleBuffer->Head->scList1; 103425aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Address_of_first_entry_2 = 103525aee3deSMauro Carvalho Chehab pIdleBuffer->Head->ngeneBuffer. 103625aee3deSMauro Carvalho Chehab Address_of_first_entry_1; 103725aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Number_of_entries_2 = 103825aee3deSMauro Carvalho Chehab pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1; 103925aee3deSMauro Carvalho Chehab Cur = Cur->Next; 104025aee3deSMauro Carvalho Chehab } 104125aee3deSMauro Carvalho Chehab return status; 104225aee3deSMauro Carvalho Chehab } 104325aee3deSMauro Carvalho Chehab 104425aee3deSMauro Carvalho Chehab static u32 RingBufferSizes[MAX_STREAM] = { 104525aee3deSMauro Carvalho Chehab RING_SIZE_VIDEO, 104625aee3deSMauro Carvalho Chehab RING_SIZE_VIDEO, 104725aee3deSMauro Carvalho Chehab RING_SIZE_AUDIO, 104825aee3deSMauro Carvalho Chehab RING_SIZE_AUDIO, 104925aee3deSMauro Carvalho Chehab RING_SIZE_AUDIO, 105025aee3deSMauro Carvalho Chehab }; 105125aee3deSMauro Carvalho Chehab 105225aee3deSMauro Carvalho Chehab static u32 Buffer1Sizes[MAX_STREAM] = { 105325aee3deSMauro Carvalho Chehab MAX_VIDEO_BUFFER_SIZE, 105425aee3deSMauro Carvalho Chehab MAX_VIDEO_BUFFER_SIZE, 105525aee3deSMauro Carvalho Chehab MAX_AUDIO_BUFFER_SIZE, 105625aee3deSMauro Carvalho Chehab MAX_AUDIO_BUFFER_SIZE, 105725aee3deSMauro Carvalho Chehab MAX_AUDIO_BUFFER_SIZE 105825aee3deSMauro Carvalho Chehab }; 105925aee3deSMauro Carvalho Chehab 106025aee3deSMauro Carvalho Chehab static u32 Buffer2Sizes[MAX_STREAM] = { 106125aee3deSMauro Carvalho Chehab MAX_VBI_BUFFER_SIZE, 106225aee3deSMauro Carvalho Chehab MAX_VBI_BUFFER_SIZE, 106325aee3deSMauro Carvalho Chehab 0, 106425aee3deSMauro Carvalho Chehab 0, 106525aee3deSMauro Carvalho Chehab 0 106625aee3deSMauro Carvalho Chehab }; 106725aee3deSMauro Carvalho Chehab 106825aee3deSMauro Carvalho Chehab 106925aee3deSMauro Carvalho Chehab static int AllocCommonBuffers(struct ngene *dev) 107025aee3deSMauro Carvalho Chehab { 107125aee3deSMauro Carvalho Chehab int status = 0, i; 107225aee3deSMauro Carvalho Chehab 107325aee3deSMauro Carvalho Chehab dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096, 107425aee3deSMauro Carvalho Chehab &dev->PAFWInterfaceBuffer); 107525aee3deSMauro Carvalho Chehab if (!dev->FWInterfaceBuffer) 107625aee3deSMauro Carvalho Chehab return -ENOMEM; 107725aee3deSMauro Carvalho Chehab dev->hosttongene = dev->FWInterfaceBuffer; 107825aee3deSMauro Carvalho Chehab dev->ngenetohost = dev->FWInterfaceBuffer + 256; 107925aee3deSMauro Carvalho Chehab dev->EventBuffer = dev->FWInterfaceBuffer + 512; 108025aee3deSMauro Carvalho Chehab 108125aee3deSMauro Carvalho Chehab dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev, 108225aee3deSMauro Carvalho Chehab OVERFLOW_BUFFER_SIZE, 108325aee3deSMauro Carvalho Chehab &dev->PAOverflowBuffer); 108425aee3deSMauro Carvalho Chehab if (!dev->OverflowBuffer) 108525aee3deSMauro Carvalho Chehab return -ENOMEM; 108625aee3deSMauro Carvalho Chehab memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE); 108725aee3deSMauro Carvalho Chehab 108825aee3deSMauro Carvalho Chehab for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { 108925aee3deSMauro Carvalho Chehab int type = dev->card_info->io_type[i]; 109025aee3deSMauro Carvalho Chehab 109125aee3deSMauro Carvalho Chehab dev->channel[i].State = KSSTATE_STOP; 109225aee3deSMauro Carvalho Chehab 109325aee3deSMauro Carvalho Chehab if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) { 109425aee3deSMauro Carvalho Chehab status = create_ring_buffer(dev->pci_dev, 109525aee3deSMauro Carvalho Chehab &dev->channel[i].RingBuffer, 109625aee3deSMauro Carvalho Chehab RingBufferSizes[i]); 109725aee3deSMauro Carvalho Chehab if (status < 0) 109825aee3deSMauro Carvalho Chehab break; 109925aee3deSMauro Carvalho Chehab 110025aee3deSMauro Carvalho Chehab if (type & (NGENE_IO_TV | NGENE_IO_AIN)) { 110125aee3deSMauro Carvalho Chehab status = AllocateRingBuffers(dev->pci_dev, 110225aee3deSMauro Carvalho Chehab dev-> 110325aee3deSMauro Carvalho Chehab PAOverflowBuffer, 110425aee3deSMauro Carvalho Chehab &dev->channel[i]. 110525aee3deSMauro Carvalho Chehab RingBuffer, 110625aee3deSMauro Carvalho Chehab Buffer1Sizes[i], 110725aee3deSMauro Carvalho Chehab Buffer2Sizes[i]); 110825aee3deSMauro Carvalho Chehab if (status < 0) 110925aee3deSMauro Carvalho Chehab break; 111025aee3deSMauro Carvalho Chehab } else if (type & NGENE_IO_HDTV) { 111125aee3deSMauro Carvalho Chehab status = AllocateRingBuffers(dev->pci_dev, 111225aee3deSMauro Carvalho Chehab dev-> 111325aee3deSMauro Carvalho Chehab PAOverflowBuffer, 111425aee3deSMauro Carvalho Chehab &dev->channel[i]. 111525aee3deSMauro Carvalho Chehab RingBuffer, 111625aee3deSMauro Carvalho Chehab MAX_HDTV_BUFFER_SIZE, 111725aee3deSMauro Carvalho Chehab 0); 111825aee3deSMauro Carvalho Chehab if (status < 0) 111925aee3deSMauro Carvalho Chehab break; 112025aee3deSMauro Carvalho Chehab } 112125aee3deSMauro Carvalho Chehab } 112225aee3deSMauro Carvalho Chehab 112325aee3deSMauro Carvalho Chehab if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { 112425aee3deSMauro Carvalho Chehab 112525aee3deSMauro Carvalho Chehab status = create_ring_buffer(dev->pci_dev, 112625aee3deSMauro Carvalho Chehab &dev->channel[i]. 112725aee3deSMauro Carvalho Chehab TSRingBuffer, RING_SIZE_TS); 112825aee3deSMauro Carvalho Chehab if (status < 0) 112925aee3deSMauro Carvalho Chehab break; 113025aee3deSMauro Carvalho Chehab 113125aee3deSMauro Carvalho Chehab status = AllocateRingBuffers(dev->pci_dev, 113225aee3deSMauro Carvalho Chehab dev->PAOverflowBuffer, 113325aee3deSMauro Carvalho Chehab &dev->channel[i]. 113425aee3deSMauro Carvalho Chehab TSRingBuffer, 113525aee3deSMauro Carvalho Chehab MAX_TS_BUFFER_SIZE, 0); 113625aee3deSMauro Carvalho Chehab if (status) 113725aee3deSMauro Carvalho Chehab break; 113825aee3deSMauro Carvalho Chehab } 113925aee3deSMauro Carvalho Chehab 114025aee3deSMauro Carvalho Chehab if (type & NGENE_IO_TSOUT) { 114125aee3deSMauro Carvalho Chehab status = create_ring_buffer(dev->pci_dev, 114225aee3deSMauro Carvalho Chehab &dev->channel[i]. 114325aee3deSMauro Carvalho Chehab TSIdleBuffer, 1); 114425aee3deSMauro Carvalho Chehab if (status < 0) 114525aee3deSMauro Carvalho Chehab break; 114625aee3deSMauro Carvalho Chehab status = AllocateRingBuffers(dev->pci_dev, 114725aee3deSMauro Carvalho Chehab dev->PAOverflowBuffer, 114825aee3deSMauro Carvalho Chehab &dev->channel[i]. 114925aee3deSMauro Carvalho Chehab TSIdleBuffer, 115025aee3deSMauro Carvalho Chehab MAX_TS_BUFFER_SIZE, 0); 115125aee3deSMauro Carvalho Chehab if (status) 115225aee3deSMauro Carvalho Chehab break; 115325aee3deSMauro Carvalho Chehab FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer, 115425aee3deSMauro Carvalho Chehab &dev->channel[i].TSRingBuffer); 115525aee3deSMauro Carvalho Chehab } 115625aee3deSMauro Carvalho Chehab } 115725aee3deSMauro Carvalho Chehab return status; 115825aee3deSMauro Carvalho Chehab } 115925aee3deSMauro Carvalho Chehab 116025aee3deSMauro Carvalho Chehab static void ngene_release_buffers(struct ngene *dev) 116125aee3deSMauro Carvalho Chehab { 116225aee3deSMauro Carvalho Chehab if (dev->iomem) 116325aee3deSMauro Carvalho Chehab iounmap(dev->iomem); 116425aee3deSMauro Carvalho Chehab free_common_buffers(dev); 116525aee3deSMauro Carvalho Chehab vfree(dev->tsout_buf); 116625aee3deSMauro Carvalho Chehab vfree(dev->tsin_buf); 116725aee3deSMauro Carvalho Chehab vfree(dev->ain_buf); 116825aee3deSMauro Carvalho Chehab vfree(dev->vin_buf); 116925aee3deSMauro Carvalho Chehab vfree(dev); 117025aee3deSMauro Carvalho Chehab } 117125aee3deSMauro Carvalho Chehab 117225aee3deSMauro Carvalho Chehab static int ngene_get_buffers(struct ngene *dev) 117325aee3deSMauro Carvalho Chehab { 117425aee3deSMauro Carvalho Chehab if (AllocCommonBuffers(dev)) 117525aee3deSMauro Carvalho Chehab return -ENOMEM; 117625aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) { 117725aee3deSMauro Carvalho Chehab dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE); 117825aee3deSMauro Carvalho Chehab if (!dev->tsout_buf) 117925aee3deSMauro Carvalho Chehab return -ENOMEM; 118025aee3deSMauro Carvalho Chehab dvb_ringbuffer_init(&dev->tsout_rbuf, 118125aee3deSMauro Carvalho Chehab dev->tsout_buf, TSOUT_BUF_SIZE); 118225aee3deSMauro Carvalho Chehab } 118325aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[2]&NGENE_IO_TSIN) { 118425aee3deSMauro Carvalho Chehab dev->tsin_buf = vmalloc(TSIN_BUF_SIZE); 118525aee3deSMauro Carvalho Chehab if (!dev->tsin_buf) 118625aee3deSMauro Carvalho Chehab return -ENOMEM; 118725aee3deSMauro Carvalho Chehab dvb_ringbuffer_init(&dev->tsin_rbuf, 118825aee3deSMauro Carvalho Chehab dev->tsin_buf, TSIN_BUF_SIZE); 118925aee3deSMauro Carvalho Chehab } 119025aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[2] & NGENE_IO_AIN) { 119125aee3deSMauro Carvalho Chehab dev->ain_buf = vmalloc(AIN_BUF_SIZE); 119225aee3deSMauro Carvalho Chehab if (!dev->ain_buf) 119325aee3deSMauro Carvalho Chehab return -ENOMEM; 119425aee3deSMauro Carvalho Chehab dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE); 119525aee3deSMauro Carvalho Chehab } 119625aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[0] & NGENE_IO_HDTV) { 119725aee3deSMauro Carvalho Chehab dev->vin_buf = vmalloc(VIN_BUF_SIZE); 119825aee3deSMauro Carvalho Chehab if (!dev->vin_buf) 119925aee3deSMauro Carvalho Chehab return -ENOMEM; 120025aee3deSMauro Carvalho Chehab dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE); 120125aee3deSMauro Carvalho Chehab } 120225aee3deSMauro Carvalho Chehab dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0), 120325aee3deSMauro Carvalho Chehab pci_resource_len(dev->pci_dev, 0)); 120425aee3deSMauro Carvalho Chehab if (!dev->iomem) 120525aee3deSMauro Carvalho Chehab return -ENOMEM; 120625aee3deSMauro Carvalho Chehab 120725aee3deSMauro Carvalho Chehab return 0; 120825aee3deSMauro Carvalho Chehab } 120925aee3deSMauro Carvalho Chehab 121025aee3deSMauro Carvalho Chehab static void ngene_init(struct ngene *dev) 121125aee3deSMauro Carvalho Chehab { 121225aee3deSMauro Carvalho Chehab int i; 121325aee3deSMauro Carvalho Chehab 121425aee3deSMauro Carvalho Chehab tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); 121525aee3deSMauro Carvalho Chehab 121625aee3deSMauro Carvalho Chehab memset_io(dev->iomem + 0xc000, 0x00, 0x220); 121725aee3deSMauro Carvalho Chehab memset_io(dev->iomem + 0xc400, 0x00, 0x100); 121825aee3deSMauro Carvalho Chehab 121925aee3deSMauro Carvalho Chehab for (i = 0; i < MAX_STREAM; i++) { 122025aee3deSMauro Carvalho Chehab dev->channel[i].dev = dev; 122125aee3deSMauro Carvalho Chehab dev->channel[i].number = i; 122225aee3deSMauro Carvalho Chehab } 122325aee3deSMauro Carvalho Chehab 122425aee3deSMauro Carvalho Chehab dev->fw_interface_version = 0; 122525aee3deSMauro Carvalho Chehab 122625aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE); 122725aee3deSMauro Carvalho Chehab 122825aee3deSMauro Carvalho Chehab dev->icounts = ngreadl(NGENE_INT_COUNTS); 122925aee3deSMauro Carvalho Chehab 123025aee3deSMauro Carvalho Chehab dev->device_version = ngreadl(DEV_VER) & 0x0f; 123125aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME ": Device version %d\n", 123225aee3deSMauro Carvalho Chehab dev->device_version); 123325aee3deSMauro Carvalho Chehab } 123425aee3deSMauro Carvalho Chehab 123525aee3deSMauro Carvalho Chehab static int ngene_load_firm(struct ngene *dev) 123625aee3deSMauro Carvalho Chehab { 123725aee3deSMauro Carvalho Chehab u32 size; 123825aee3deSMauro Carvalho Chehab const struct firmware *fw = NULL; 123925aee3deSMauro Carvalho Chehab u8 *ngene_fw; 124025aee3deSMauro Carvalho Chehab char *fw_name; 124125aee3deSMauro Carvalho Chehab int err, version; 124225aee3deSMauro Carvalho Chehab 124325aee3deSMauro Carvalho Chehab version = dev->card_info->fw_version; 124425aee3deSMauro Carvalho Chehab 124525aee3deSMauro Carvalho Chehab switch (version) { 124625aee3deSMauro Carvalho Chehab default: 124725aee3deSMauro Carvalho Chehab case 15: 124825aee3deSMauro Carvalho Chehab version = 15; 124925aee3deSMauro Carvalho Chehab size = 23466; 125025aee3deSMauro Carvalho Chehab fw_name = "ngene_15.fw"; 125125aee3deSMauro Carvalho Chehab dev->cmd_timeout_workaround = true; 125225aee3deSMauro Carvalho Chehab break; 125325aee3deSMauro Carvalho Chehab case 16: 125425aee3deSMauro Carvalho Chehab size = 23498; 125525aee3deSMauro Carvalho Chehab fw_name = "ngene_16.fw"; 125625aee3deSMauro Carvalho Chehab dev->cmd_timeout_workaround = true; 125725aee3deSMauro Carvalho Chehab break; 125825aee3deSMauro Carvalho Chehab case 17: 125925aee3deSMauro Carvalho Chehab size = 24446; 126025aee3deSMauro Carvalho Chehab fw_name = "ngene_17.fw"; 126125aee3deSMauro Carvalho Chehab dev->cmd_timeout_workaround = true; 126225aee3deSMauro Carvalho Chehab break; 126325aee3deSMauro Carvalho Chehab case 18: 126425aee3deSMauro Carvalho Chehab size = 0; 126525aee3deSMauro Carvalho Chehab fw_name = "ngene_18.fw"; 126625aee3deSMauro Carvalho Chehab break; 126725aee3deSMauro Carvalho Chehab } 126825aee3deSMauro Carvalho Chehab 126925aee3deSMauro Carvalho Chehab if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { 127025aee3deSMauro Carvalho Chehab printk(KERN_ERR DEVICE_NAME 127125aee3deSMauro Carvalho Chehab ": Could not load firmware file %s.\n", fw_name); 127225aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME 127325aee3deSMauro Carvalho Chehab ": Copy %s to your hotplug directory!\n", fw_name); 127425aee3deSMauro Carvalho Chehab return -1; 127525aee3deSMauro Carvalho Chehab } 127625aee3deSMauro Carvalho Chehab if (size == 0) 127725aee3deSMauro Carvalho Chehab size = fw->size; 127825aee3deSMauro Carvalho Chehab if (size != fw->size) { 127925aee3deSMauro Carvalho Chehab printk(KERN_ERR DEVICE_NAME 128025aee3deSMauro Carvalho Chehab ": Firmware %s has invalid size!", fw_name); 128125aee3deSMauro Carvalho Chehab err = -1; 128225aee3deSMauro Carvalho Chehab } else { 128325aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME 128425aee3deSMauro Carvalho Chehab ": Loading firmware file %s.\n", fw_name); 128525aee3deSMauro Carvalho Chehab ngene_fw = (u8 *) fw->data; 128625aee3deSMauro Carvalho Chehab err = ngene_command_load_firmware(dev, ngene_fw, size); 128725aee3deSMauro Carvalho Chehab } 128825aee3deSMauro Carvalho Chehab 128925aee3deSMauro Carvalho Chehab release_firmware(fw); 129025aee3deSMauro Carvalho Chehab 129125aee3deSMauro Carvalho Chehab return err; 129225aee3deSMauro Carvalho Chehab } 129325aee3deSMauro Carvalho Chehab 129425aee3deSMauro Carvalho Chehab static void ngene_stop(struct ngene *dev) 129525aee3deSMauro Carvalho Chehab { 129625aee3deSMauro Carvalho Chehab down(&dev->cmd_mutex); 129725aee3deSMauro Carvalho Chehab i2c_del_adapter(&(dev->channel[0].i2c_adapter)); 129825aee3deSMauro Carvalho Chehab i2c_del_adapter(&(dev->channel[1].i2c_adapter)); 129925aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE); 130025aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_COMMAND); 130125aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_COMMAND_HI); 130225aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_STATUS); 130325aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_STATUS_HI); 130425aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_EVENT); 130525aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_EVENT_HI); 130625aee3deSMauro Carvalho Chehab free_irq(dev->pci_dev->irq, dev); 130725aee3deSMauro Carvalho Chehab #ifdef CONFIG_PCI_MSI 130825aee3deSMauro Carvalho Chehab if (dev->msi_enabled) 130925aee3deSMauro Carvalho Chehab pci_disable_msi(dev->pci_dev); 131025aee3deSMauro Carvalho Chehab #endif 131125aee3deSMauro Carvalho Chehab } 131225aee3deSMauro Carvalho Chehab 131325aee3deSMauro Carvalho Chehab static int ngene_buffer_config(struct ngene *dev) 131425aee3deSMauro Carvalho Chehab { 131525aee3deSMauro Carvalho Chehab int stat; 131625aee3deSMauro Carvalho Chehab 131725aee3deSMauro Carvalho Chehab if (dev->card_info->fw_version >= 17) { 131825aee3deSMauro Carvalho Chehab u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }; 131925aee3deSMauro Carvalho Chehab u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 }; 132025aee3deSMauro Carvalho Chehab u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 }; 132125aee3deSMauro Carvalho Chehab u8 *bconf = tsin12_config; 132225aee3deSMauro Carvalho Chehab 132325aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[2]&NGENE_IO_TSIN && 132425aee3deSMauro Carvalho Chehab dev->card_info->io_type[3]&NGENE_IO_TSIN) { 132525aee3deSMauro Carvalho Chehab bconf = tsin1234_config; 132625aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[4]&NGENE_IO_TSOUT && 132725aee3deSMauro Carvalho Chehab dev->ci.en) 132825aee3deSMauro Carvalho Chehab bconf = tsio1235_config; 132925aee3deSMauro Carvalho Chehab } 133025aee3deSMauro Carvalho Chehab stat = ngene_command_config_free_buf(dev, bconf); 133125aee3deSMauro Carvalho Chehab } else { 133225aee3deSMauro Carvalho Chehab int bconf = BUFFER_CONFIG_4422; 133325aee3deSMauro Carvalho Chehab 133425aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[3] == NGENE_IO_TSIN) 133525aee3deSMauro Carvalho Chehab bconf = BUFFER_CONFIG_3333; 133625aee3deSMauro Carvalho Chehab stat = ngene_command_config_buf(dev, bconf); 133725aee3deSMauro Carvalho Chehab } 133825aee3deSMauro Carvalho Chehab return stat; 133925aee3deSMauro Carvalho Chehab } 134025aee3deSMauro Carvalho Chehab 134125aee3deSMauro Carvalho Chehab 134225aee3deSMauro Carvalho Chehab static int ngene_start(struct ngene *dev) 134325aee3deSMauro Carvalho Chehab { 134425aee3deSMauro Carvalho Chehab int stat; 134525aee3deSMauro Carvalho Chehab int i; 134625aee3deSMauro Carvalho Chehab 134725aee3deSMauro Carvalho Chehab pci_set_master(dev->pci_dev); 134825aee3deSMauro Carvalho Chehab ngene_init(dev); 134925aee3deSMauro Carvalho Chehab 135025aee3deSMauro Carvalho Chehab stat = request_irq(dev->pci_dev->irq, irq_handler, 135125aee3deSMauro Carvalho Chehab IRQF_SHARED, "nGene", 135225aee3deSMauro Carvalho Chehab (void *)dev); 135325aee3deSMauro Carvalho Chehab if (stat < 0) 135425aee3deSMauro Carvalho Chehab return stat; 135525aee3deSMauro Carvalho Chehab 135625aee3deSMauro Carvalho Chehab init_waitqueue_head(&dev->cmd_wq); 135725aee3deSMauro Carvalho Chehab init_waitqueue_head(&dev->tx_wq); 135825aee3deSMauro Carvalho Chehab init_waitqueue_head(&dev->rx_wq); 135925aee3deSMauro Carvalho Chehab sema_init(&dev->cmd_mutex, 1); 136025aee3deSMauro Carvalho Chehab sema_init(&dev->stream_mutex, 1); 136125aee3deSMauro Carvalho Chehab sema_init(&dev->pll_mutex, 1); 136225aee3deSMauro Carvalho Chehab sema_init(&dev->i2c_switch_mutex, 1); 136325aee3deSMauro Carvalho Chehab spin_lock_init(&dev->cmd_lock); 136425aee3deSMauro Carvalho Chehab for (i = 0; i < MAX_STREAM; i++) 136525aee3deSMauro Carvalho Chehab spin_lock_init(&dev->channel[i].state_lock); 136625aee3deSMauro Carvalho Chehab ngwritel(1, TIMESTAMPS); 136725aee3deSMauro Carvalho Chehab 136825aee3deSMauro Carvalho Chehab ngwritel(1, NGENE_INT_ENABLE); 136925aee3deSMauro Carvalho Chehab 137025aee3deSMauro Carvalho Chehab stat = ngene_load_firm(dev); 137125aee3deSMauro Carvalho Chehab if (stat < 0) 137225aee3deSMauro Carvalho Chehab goto fail; 137325aee3deSMauro Carvalho Chehab 137425aee3deSMauro Carvalho Chehab #ifdef CONFIG_PCI_MSI 137525aee3deSMauro Carvalho Chehab /* enable MSI if kernel and card support it */ 137625aee3deSMauro Carvalho Chehab if (pci_msi_enabled() && dev->card_info->msi_supported) { 137725aee3deSMauro Carvalho Chehab unsigned long flags; 137825aee3deSMauro Carvalho Chehab 137925aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE); 138025aee3deSMauro Carvalho Chehab free_irq(dev->pci_dev->irq, dev); 138125aee3deSMauro Carvalho Chehab stat = pci_enable_msi(dev->pci_dev); 138225aee3deSMauro Carvalho Chehab if (stat) { 138325aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME 138425aee3deSMauro Carvalho Chehab ": MSI not available\n"); 138525aee3deSMauro Carvalho Chehab flags = IRQF_SHARED; 138625aee3deSMauro Carvalho Chehab } else { 138725aee3deSMauro Carvalho Chehab flags = 0; 138825aee3deSMauro Carvalho Chehab dev->msi_enabled = true; 138925aee3deSMauro Carvalho Chehab } 139025aee3deSMauro Carvalho Chehab stat = request_irq(dev->pci_dev->irq, irq_handler, 139125aee3deSMauro Carvalho Chehab flags, "nGene", dev); 139225aee3deSMauro Carvalho Chehab if (stat < 0) 139325aee3deSMauro Carvalho Chehab goto fail2; 139425aee3deSMauro Carvalho Chehab ngwritel(1, NGENE_INT_ENABLE); 139525aee3deSMauro Carvalho Chehab } 139625aee3deSMauro Carvalho Chehab #endif 139725aee3deSMauro Carvalho Chehab 139825aee3deSMauro Carvalho Chehab stat = ngene_i2c_init(dev, 0); 139925aee3deSMauro Carvalho Chehab if (stat < 0) 140025aee3deSMauro Carvalho Chehab goto fail; 140125aee3deSMauro Carvalho Chehab 140225aee3deSMauro Carvalho Chehab stat = ngene_i2c_init(dev, 1); 140325aee3deSMauro Carvalho Chehab if (stat < 0) 140425aee3deSMauro Carvalho Chehab goto fail; 140525aee3deSMauro Carvalho Chehab 140625aee3deSMauro Carvalho Chehab return 0; 140725aee3deSMauro Carvalho Chehab 140825aee3deSMauro Carvalho Chehab fail: 140925aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE); 141025aee3deSMauro Carvalho Chehab free_irq(dev->pci_dev->irq, dev); 141125aee3deSMauro Carvalho Chehab #ifdef CONFIG_PCI_MSI 141225aee3deSMauro Carvalho Chehab fail2: 141325aee3deSMauro Carvalho Chehab if (dev->msi_enabled) 141425aee3deSMauro Carvalho Chehab pci_disable_msi(dev->pci_dev); 141525aee3deSMauro Carvalho Chehab #endif 141625aee3deSMauro Carvalho Chehab return stat; 141725aee3deSMauro Carvalho Chehab } 141825aee3deSMauro Carvalho Chehab 141925aee3deSMauro Carvalho Chehab /****************************************************************************/ 142025aee3deSMauro Carvalho Chehab /****************************************************************************/ 142125aee3deSMauro Carvalho Chehab /****************************************************************************/ 142225aee3deSMauro Carvalho Chehab 142325aee3deSMauro Carvalho Chehab static void release_channel(struct ngene_channel *chan) 142425aee3deSMauro Carvalho Chehab { 142525aee3deSMauro Carvalho Chehab struct dvb_demux *dvbdemux = &chan->demux; 142625aee3deSMauro Carvalho Chehab struct ngene *dev = chan->dev; 142725aee3deSMauro Carvalho Chehab 142825aee3deSMauro Carvalho Chehab if (chan->running) 142925aee3deSMauro Carvalho Chehab set_transfer(chan, 0); 143025aee3deSMauro Carvalho Chehab 143125aee3deSMauro Carvalho Chehab tasklet_kill(&chan->demux_tasklet); 143225aee3deSMauro Carvalho Chehab 143325aee3deSMauro Carvalho Chehab if (chan->ci_dev) { 143425aee3deSMauro Carvalho Chehab dvb_unregister_device(chan->ci_dev); 143525aee3deSMauro Carvalho Chehab chan->ci_dev = NULL; 143625aee3deSMauro Carvalho Chehab } 143725aee3deSMauro Carvalho Chehab 143825aee3deSMauro Carvalho Chehab if (chan->fe2) 143925aee3deSMauro Carvalho Chehab dvb_unregister_frontend(chan->fe2); 144025aee3deSMauro Carvalho Chehab 144125aee3deSMauro Carvalho Chehab if (chan->fe) { 144225aee3deSMauro Carvalho Chehab dvb_unregister_frontend(chan->fe); 144325aee3deSMauro Carvalho Chehab dvb_frontend_detach(chan->fe); 144425aee3deSMauro Carvalho Chehab chan->fe = NULL; 144525aee3deSMauro Carvalho Chehab } 144625aee3deSMauro Carvalho Chehab 144725aee3deSMauro Carvalho Chehab if (chan->has_demux) { 144825aee3deSMauro Carvalho Chehab dvb_net_release(&chan->dvbnet); 144925aee3deSMauro Carvalho Chehab dvbdemux->dmx.close(&dvbdemux->dmx); 145025aee3deSMauro Carvalho Chehab dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, 145125aee3deSMauro Carvalho Chehab &chan->hw_frontend); 145225aee3deSMauro Carvalho Chehab dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, 145325aee3deSMauro Carvalho Chehab &chan->mem_frontend); 145425aee3deSMauro Carvalho Chehab dvb_dmxdev_release(&chan->dmxdev); 145525aee3deSMauro Carvalho Chehab dvb_dmx_release(&chan->demux); 145625aee3deSMauro Carvalho Chehab chan->has_demux = false; 145725aee3deSMauro Carvalho Chehab } 145825aee3deSMauro Carvalho Chehab 145925aee3deSMauro Carvalho Chehab if (chan->has_adapter) { 146025aee3deSMauro Carvalho Chehab dvb_unregister_adapter(&dev->adapter[chan->number]); 146125aee3deSMauro Carvalho Chehab chan->has_adapter = false; 146225aee3deSMauro Carvalho Chehab } 146325aee3deSMauro Carvalho Chehab } 146425aee3deSMauro Carvalho Chehab 146525aee3deSMauro Carvalho Chehab static int init_channel(struct ngene_channel *chan) 146625aee3deSMauro Carvalho Chehab { 146725aee3deSMauro Carvalho Chehab int ret = 0, nr = chan->number; 146825aee3deSMauro Carvalho Chehab struct dvb_adapter *adapter = NULL; 146925aee3deSMauro Carvalho Chehab struct dvb_demux *dvbdemux = &chan->demux; 147025aee3deSMauro Carvalho Chehab struct ngene *dev = chan->dev; 147125aee3deSMauro Carvalho Chehab struct ngene_info *ni = dev->card_info; 147225aee3deSMauro Carvalho Chehab int io = ni->io_type[nr]; 147325aee3deSMauro Carvalho Chehab 147425aee3deSMauro Carvalho Chehab tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan); 147525aee3deSMauro Carvalho Chehab chan->users = 0; 147625aee3deSMauro Carvalho Chehab chan->type = io; 147725aee3deSMauro Carvalho Chehab chan->mode = chan->type; /* for now only one mode */ 147825aee3deSMauro Carvalho Chehab 147925aee3deSMauro Carvalho Chehab if (io & NGENE_IO_TSIN) { 148025aee3deSMauro Carvalho Chehab chan->fe = NULL; 148125aee3deSMauro Carvalho Chehab if (ni->demod_attach[nr]) { 148225aee3deSMauro Carvalho Chehab ret = ni->demod_attach[nr](chan); 148325aee3deSMauro Carvalho Chehab if (ret < 0) 148425aee3deSMauro Carvalho Chehab goto err; 148525aee3deSMauro Carvalho Chehab } 148625aee3deSMauro Carvalho Chehab if (chan->fe && ni->tuner_attach[nr]) { 148725aee3deSMauro Carvalho Chehab ret = ni->tuner_attach[nr](chan); 148825aee3deSMauro Carvalho Chehab if (ret < 0) 148925aee3deSMauro Carvalho Chehab goto err; 149025aee3deSMauro Carvalho Chehab } 149125aee3deSMauro Carvalho Chehab } 149225aee3deSMauro Carvalho Chehab 149325aee3deSMauro Carvalho Chehab if (!dev->ci.en && (io & NGENE_IO_TSOUT)) 149425aee3deSMauro Carvalho Chehab return 0; 149525aee3deSMauro Carvalho Chehab 149625aee3deSMauro Carvalho Chehab if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { 149725aee3deSMauro Carvalho Chehab if (nr >= STREAM_AUDIOIN1) 149825aee3deSMauro Carvalho Chehab chan->DataFormatFlags = DF_SWAP32; 149925aee3deSMauro Carvalho Chehab 150025aee3deSMauro Carvalho Chehab if (nr == 0 || !one_adapter || dev->first_adapter == NULL) { 150125aee3deSMauro Carvalho Chehab adapter = &dev->adapter[nr]; 150225aee3deSMauro Carvalho Chehab ret = dvb_register_adapter(adapter, "nGene", 150325aee3deSMauro Carvalho Chehab THIS_MODULE, 150425aee3deSMauro Carvalho Chehab &chan->dev->pci_dev->dev, 150525aee3deSMauro Carvalho Chehab adapter_nr); 150625aee3deSMauro Carvalho Chehab if (ret < 0) 150725aee3deSMauro Carvalho Chehab goto err; 150825aee3deSMauro Carvalho Chehab if (dev->first_adapter == NULL) 150925aee3deSMauro Carvalho Chehab dev->first_adapter = adapter; 151025aee3deSMauro Carvalho Chehab chan->has_adapter = true; 151125aee3deSMauro Carvalho Chehab } else 151225aee3deSMauro Carvalho Chehab adapter = dev->first_adapter; 151325aee3deSMauro Carvalho Chehab } 151425aee3deSMauro Carvalho Chehab 151525aee3deSMauro Carvalho Chehab if (dev->ci.en && (io & NGENE_IO_TSOUT)) { 151625aee3deSMauro Carvalho Chehab dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); 151725aee3deSMauro Carvalho Chehab set_transfer(chan, 1); 151825aee3deSMauro Carvalho Chehab chan->dev->channel[2].DataFormatFlags = DF_SWAP32; 151925aee3deSMauro Carvalho Chehab set_transfer(&chan->dev->channel[2], 1); 152025aee3deSMauro Carvalho Chehab dvb_register_device(adapter, &chan->ci_dev, 152125aee3deSMauro Carvalho Chehab &ngene_dvbdev_ci, (void *) chan, 152225aee3deSMauro Carvalho Chehab DVB_DEVICE_SEC); 152325aee3deSMauro Carvalho Chehab if (!chan->ci_dev) 152425aee3deSMauro Carvalho Chehab goto err; 152525aee3deSMauro Carvalho Chehab } 152625aee3deSMauro Carvalho Chehab 152725aee3deSMauro Carvalho Chehab if (chan->fe) { 152825aee3deSMauro Carvalho Chehab if (dvb_register_frontend(adapter, chan->fe) < 0) 152925aee3deSMauro Carvalho Chehab goto err; 153025aee3deSMauro Carvalho Chehab chan->has_demux = true; 153125aee3deSMauro Carvalho Chehab } 153225aee3deSMauro Carvalho Chehab if (chan->fe2) { 153325aee3deSMauro Carvalho Chehab if (dvb_register_frontend(adapter, chan->fe2) < 0) 153425aee3deSMauro Carvalho Chehab goto err; 153525aee3deSMauro Carvalho Chehab chan->fe2->tuner_priv = chan->fe->tuner_priv; 153625aee3deSMauro Carvalho Chehab memcpy(&chan->fe2->ops.tuner_ops, 153725aee3deSMauro Carvalho Chehab &chan->fe->ops.tuner_ops, 153825aee3deSMauro Carvalho Chehab sizeof(struct dvb_tuner_ops)); 153925aee3deSMauro Carvalho Chehab } 154025aee3deSMauro Carvalho Chehab 154125aee3deSMauro Carvalho Chehab if (chan->has_demux) { 154225aee3deSMauro Carvalho Chehab ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", 154325aee3deSMauro Carvalho Chehab ngene_start_feed, 154425aee3deSMauro Carvalho Chehab ngene_stop_feed, chan); 154525aee3deSMauro Carvalho Chehab ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, 154625aee3deSMauro Carvalho Chehab &chan->hw_frontend, 154725aee3deSMauro Carvalho Chehab &chan->mem_frontend, adapter); 154825aee3deSMauro Carvalho Chehab ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); 154925aee3deSMauro Carvalho Chehab } 155025aee3deSMauro Carvalho Chehab 155125aee3deSMauro Carvalho Chehab return ret; 155225aee3deSMauro Carvalho Chehab 155325aee3deSMauro Carvalho Chehab err: 155425aee3deSMauro Carvalho Chehab if (chan->fe) { 155525aee3deSMauro Carvalho Chehab dvb_frontend_detach(chan->fe); 155625aee3deSMauro Carvalho Chehab chan->fe = NULL; 155725aee3deSMauro Carvalho Chehab } 155825aee3deSMauro Carvalho Chehab release_channel(chan); 155925aee3deSMauro Carvalho Chehab return 0; 156025aee3deSMauro Carvalho Chehab } 156125aee3deSMauro Carvalho Chehab 156225aee3deSMauro Carvalho Chehab static int init_channels(struct ngene *dev) 156325aee3deSMauro Carvalho Chehab { 156425aee3deSMauro Carvalho Chehab int i, j; 156525aee3deSMauro Carvalho Chehab 156625aee3deSMauro Carvalho Chehab for (i = 0; i < MAX_STREAM; i++) { 156725aee3deSMauro Carvalho Chehab dev->channel[i].number = i; 156825aee3deSMauro Carvalho Chehab if (init_channel(&dev->channel[i]) < 0) { 156925aee3deSMauro Carvalho Chehab for (j = i - 1; j >= 0; j--) 157025aee3deSMauro Carvalho Chehab release_channel(&dev->channel[j]); 157125aee3deSMauro Carvalho Chehab return -1; 157225aee3deSMauro Carvalho Chehab } 157325aee3deSMauro Carvalho Chehab } 157425aee3deSMauro Carvalho Chehab return 0; 157525aee3deSMauro Carvalho Chehab } 157625aee3deSMauro Carvalho Chehab 157725aee3deSMauro Carvalho Chehab static struct cxd2099_cfg cxd_cfg = { 157825aee3deSMauro Carvalho Chehab .bitrate = 62000, 157925aee3deSMauro Carvalho Chehab .adr = 0x40, 158025aee3deSMauro Carvalho Chehab .polarity = 0, 158125aee3deSMauro Carvalho Chehab .clock_mode = 0, 158225aee3deSMauro Carvalho Chehab }; 158325aee3deSMauro Carvalho Chehab 158425aee3deSMauro Carvalho Chehab static void cxd_attach(struct ngene *dev) 158525aee3deSMauro Carvalho Chehab { 158625aee3deSMauro Carvalho Chehab struct ngene_ci *ci = &dev->ci; 158725aee3deSMauro Carvalho Chehab 158825aee3deSMauro Carvalho Chehab ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); 158925aee3deSMauro Carvalho Chehab ci->dev = dev; 159025aee3deSMauro Carvalho Chehab return; 159125aee3deSMauro Carvalho Chehab } 159225aee3deSMauro Carvalho Chehab 159325aee3deSMauro Carvalho Chehab static void cxd_detach(struct ngene *dev) 159425aee3deSMauro Carvalho Chehab { 159525aee3deSMauro Carvalho Chehab struct ngene_ci *ci = &dev->ci; 159625aee3deSMauro Carvalho Chehab 159725aee3deSMauro Carvalho Chehab dvb_ca_en50221_release(ci->en); 159825aee3deSMauro Carvalho Chehab kfree(ci->en); 159925aee3deSMauro Carvalho Chehab ci->en = 0; 160025aee3deSMauro Carvalho Chehab } 160125aee3deSMauro Carvalho Chehab 160225aee3deSMauro Carvalho Chehab /***********************************/ 160325aee3deSMauro Carvalho Chehab /* workaround for shutdown failure */ 160425aee3deSMauro Carvalho Chehab /***********************************/ 160525aee3deSMauro Carvalho Chehab 160625aee3deSMauro Carvalho Chehab static void ngene_unlink(struct ngene *dev) 160725aee3deSMauro Carvalho Chehab { 160825aee3deSMauro Carvalho Chehab struct ngene_command com; 160925aee3deSMauro Carvalho Chehab 161025aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_MEM_WRITE; 161125aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 3; 161225aee3deSMauro Carvalho Chehab com.cmd.MemoryWrite.address = 0x910c; 161325aee3deSMauro Carvalho Chehab com.cmd.MemoryWrite.data = 0xff; 161425aee3deSMauro Carvalho Chehab com.in_len = 3; 161525aee3deSMauro Carvalho Chehab com.out_len = 1; 161625aee3deSMauro Carvalho Chehab 161725aee3deSMauro Carvalho Chehab down(&dev->cmd_mutex); 161825aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE); 161925aee3deSMauro Carvalho Chehab ngene_command_mutex(dev, &com); 162025aee3deSMauro Carvalho Chehab up(&dev->cmd_mutex); 162125aee3deSMauro Carvalho Chehab } 162225aee3deSMauro Carvalho Chehab 162325aee3deSMauro Carvalho Chehab void ngene_shutdown(struct pci_dev *pdev) 162425aee3deSMauro Carvalho Chehab { 162525aee3deSMauro Carvalho Chehab struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev); 162625aee3deSMauro Carvalho Chehab 162725aee3deSMauro Carvalho Chehab if (!dev || !shutdown_workaround) 162825aee3deSMauro Carvalho Chehab return; 162925aee3deSMauro Carvalho Chehab 163025aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); 163125aee3deSMauro Carvalho Chehab ngene_unlink(dev); 163225aee3deSMauro Carvalho Chehab pci_disable_device(pdev); 163325aee3deSMauro Carvalho Chehab } 163425aee3deSMauro Carvalho Chehab 163525aee3deSMauro Carvalho Chehab /****************************************************************************/ 163625aee3deSMauro Carvalho Chehab /* device probe/remove calls ************************************************/ 163725aee3deSMauro Carvalho Chehab /****************************************************************************/ 163825aee3deSMauro Carvalho Chehab 163925aee3deSMauro Carvalho Chehab void __devexit ngene_remove(struct pci_dev *pdev) 164025aee3deSMauro Carvalho Chehab { 164125aee3deSMauro Carvalho Chehab struct ngene *dev = pci_get_drvdata(pdev); 164225aee3deSMauro Carvalho Chehab int i; 164325aee3deSMauro Carvalho Chehab 164425aee3deSMauro Carvalho Chehab tasklet_kill(&dev->event_tasklet); 164525aee3deSMauro Carvalho Chehab for (i = MAX_STREAM - 1; i >= 0; i--) 164625aee3deSMauro Carvalho Chehab release_channel(&dev->channel[i]); 164725aee3deSMauro Carvalho Chehab if (dev->ci.en) 164825aee3deSMauro Carvalho Chehab cxd_detach(dev); 164925aee3deSMauro Carvalho Chehab ngene_stop(dev); 165025aee3deSMauro Carvalho Chehab ngene_release_buffers(dev); 165125aee3deSMauro Carvalho Chehab pci_set_drvdata(pdev, NULL); 165225aee3deSMauro Carvalho Chehab pci_disable_device(pdev); 165325aee3deSMauro Carvalho Chehab } 165425aee3deSMauro Carvalho Chehab 165525aee3deSMauro Carvalho Chehab int __devinit ngene_probe(struct pci_dev *pci_dev, 165625aee3deSMauro Carvalho Chehab const struct pci_device_id *id) 165725aee3deSMauro Carvalho Chehab { 165825aee3deSMauro Carvalho Chehab struct ngene *dev; 165925aee3deSMauro Carvalho Chehab int stat = 0; 166025aee3deSMauro Carvalho Chehab 166125aee3deSMauro Carvalho Chehab if (pci_enable_device(pci_dev) < 0) 166225aee3deSMauro Carvalho Chehab return -ENODEV; 166325aee3deSMauro Carvalho Chehab 166425aee3deSMauro Carvalho Chehab dev = vzalloc(sizeof(struct ngene)); 166525aee3deSMauro Carvalho Chehab if (dev == NULL) { 166625aee3deSMauro Carvalho Chehab stat = -ENOMEM; 166725aee3deSMauro Carvalho Chehab goto fail0; 166825aee3deSMauro Carvalho Chehab } 166925aee3deSMauro Carvalho Chehab 167025aee3deSMauro Carvalho Chehab dev->pci_dev = pci_dev; 167125aee3deSMauro Carvalho Chehab dev->card_info = (struct ngene_info *)id->driver_data; 167225aee3deSMauro Carvalho Chehab printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); 167325aee3deSMauro Carvalho Chehab 167425aee3deSMauro Carvalho Chehab pci_set_drvdata(pci_dev, dev); 167525aee3deSMauro Carvalho Chehab 167625aee3deSMauro Carvalho Chehab /* Alloc buffers and start nGene */ 167725aee3deSMauro Carvalho Chehab stat = ngene_get_buffers(dev); 167825aee3deSMauro Carvalho Chehab if (stat < 0) 167925aee3deSMauro Carvalho Chehab goto fail1; 168025aee3deSMauro Carvalho Chehab stat = ngene_start(dev); 168125aee3deSMauro Carvalho Chehab if (stat < 0) 168225aee3deSMauro Carvalho Chehab goto fail1; 168325aee3deSMauro Carvalho Chehab 168425aee3deSMauro Carvalho Chehab cxd_attach(dev); 168525aee3deSMauro Carvalho Chehab 168625aee3deSMauro Carvalho Chehab stat = ngene_buffer_config(dev); 168725aee3deSMauro Carvalho Chehab if (stat < 0) 168825aee3deSMauro Carvalho Chehab goto fail1; 168925aee3deSMauro Carvalho Chehab 169025aee3deSMauro Carvalho Chehab 169125aee3deSMauro Carvalho Chehab dev->i2c_current_bus = -1; 169225aee3deSMauro Carvalho Chehab 169325aee3deSMauro Carvalho Chehab /* Register DVB adapters and devices for both channels */ 169425aee3deSMauro Carvalho Chehab if (init_channels(dev) < 0) 169525aee3deSMauro Carvalho Chehab goto fail2; 169625aee3deSMauro Carvalho Chehab 169725aee3deSMauro Carvalho Chehab return 0; 169825aee3deSMauro Carvalho Chehab 169925aee3deSMauro Carvalho Chehab fail2: 170025aee3deSMauro Carvalho Chehab ngene_stop(dev); 170125aee3deSMauro Carvalho Chehab fail1: 170225aee3deSMauro Carvalho Chehab ngene_release_buffers(dev); 170325aee3deSMauro Carvalho Chehab fail0: 170425aee3deSMauro Carvalho Chehab pci_disable_device(pci_dev); 170525aee3deSMauro Carvalho Chehab pci_set_drvdata(pci_dev, NULL); 170625aee3deSMauro Carvalho Chehab return stat; 170725aee3deSMauro Carvalho Chehab } 1708