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