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