Mailing List archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[linux-dvb] [PATCH] dvb-ttpci+budgetpatch integrated v22
HI
Naming of dvbnet devices is fixed, they are
now called dvb000 for net0 and dvb010 for net1
("_" in the middle of dvb0_0 is used to indicate
id of net* interface)
Otherwise it all works as ordinary dvb-ttpci,
vdr etc. work as before, except dvbnet can be
registered using full TS speed net1
This can be adapted to work for dvb-s 2.1+
perhaps without any hardware modifiication so
owners of those cards can enyoj full ts.
For CVS
-------------------------------
dvb-ttpci is extended with second demux on
port B of 7146, named demux1,
with accompanying net1 and dvr1 devices.
This allows full ts data transmission running in
parallel with all prior functions of dvb-s.
Runs on dvb-s 1.x with budget patch and dvb-s >=2.1
perhaps without any modification if those cards
are manufactured with divider chips onboard.
For unmodified 1.X cards this patch is a no-op.
demux1 exists but receives no data.
Naming convention of dvb0_0 has to be changed
to dvb000, middle digit indicating net0 and
dvb010 for net1.
-------------------------------
Emard
Only in dvb-kernel/linux/drivers/media/dvb/dvb-core: DEADJOE
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dvb_net.c dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_net.c
--- dvb-kernel.orig/linux/drivers/media/dvb/dvb-core/dvb_net.c 2005-01-02 18:44:41.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_net.c 2005-01-03 13:25:54.000000000 +0100
@@ -1157,18 +1157,26 @@ static int dvb_net_add_if(struct dvb_net
struct dvb_net_priv *priv;
int result;
int if_num;
-
+ char name[20];
+
+ memset(name, 0, sizeof(name));
+
if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE)
return -EINVAL;
if ((if_num = get_if(dvbnet)) < 0)
return -EINVAL;
- net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb",
+ sprintf(name, "dvb%1d%1d%1d",
+ dvbnet->dvbdev->adapter->num,
+ dvbnet->dvbdev->id,
+ if_num);
+
+ net = alloc_netdev(sizeof(struct dvb_net_priv), name,
dvb_net_setup);
if (!net)
return -ENOMEM;
- sprintf(net->name, "dvb%d_%d", dvbnet->dvbdev->adapter->num, if_num);
+ sprintf(net->name, "%s", name);
net->addr_len = 6;
memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
Only in dvb-kernel/linux/drivers/media/dvb/dvb-core: dvb_net.c~
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: Makefile~
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/av7110.c dvb-kernel/linux/drivers/media/dvb/ttpci/av7110.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/av7110.c 2005-01-02 18:44:41.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/av7110.c 2005-01-03 12:11:01.000000000 +0100
@@ -66,6 +66,10 @@
#include "av7110_av.h"
#include "av7110_ca.h"
#include "av7110_ipack.h"
+#define TS_WIDTH (376)
+#define TS_HEIGHT (512)
+#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
+#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE)
int av7110_debug;
@@ -1136,11 +1140,121 @@ static int av7110_diseqc_send_burst(stru
return 0;
}
+/* Hi, this is Emard and have mostly
+** copy/pasted those budget routines from
+** budget-core.c with struct names slightly accomodated.
+** I tried to link it in makefile
+** but just it doesn't work for me, the include/link
+** structure seems to be beyond my understanding!
+*/
+static int stop_ts_capture(struct av7110 *budget)
+{
+ dprintk(2, "budget: %p\n", budget);
+
+ printk("Stop: Event Counter 1 0x%04x\n", saa7146_read(budget->dev, EC1R) & 0x3fff );
+
+ if (--budget->feeding1)
+ return budget->feeding1;
+
+ saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off
+ SAA7146_IER_DISABLE(budget->dev, MASK_10);
+ return 0;
+}
+
+static int start_ts_capture(struct av7110 *budget)
+{
+ struct saa7146_dev *dev = budget->dev;
+
+ dprintk(2, "budget: %p\n", budget);
+
+ printk("Start: Event Counter 1 0x%04x\n", saa7146_read(budget->dev, EC1R) & 0x3fff );
+
+ if (budget->feeding1)
+ return ++budget->feeding1;
+
+ memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
+
+ budget->tsf = 0xff;
+ budget->ttbp = 0;
+
+ saa7146_write(dev, MC1, (MASK_04 | MASK_20)); // DMA3 on
+
+ SAA7146_IER_ENABLE(budget->dev, MASK_10); // VPE
+
+ return ++budget->feeding1;
+}
+
+static int budget_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct av7110 *budget = (struct av7110 *) demux->priv;
+ int status;
+
+ dprintk(2, "av7110: %p\n", budget);
+
+ printk("start feed\n");
+#if 0
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+#endif
+ spin_lock(&budget->feedlock1);
+ status = start_ts_capture(budget);
+ spin_unlock(&budget->feedlock1);
+ return status;
+}
+
+static int budget_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct av7110 *budget = (struct av7110 *) demux->priv;
+ int status;
+
+ dprintk(2, "budget: %p\n", budget);
+
+ spin_lock(&budget->feedlock1);
+ status = stop_ts_capture(budget);
+ spin_unlock(&budget->feedlock1);
+ return status;
+}
+
+
+static void vpeirq(unsigned long data)
+{
+ struct av7110 *budget = (struct av7110 *) data;
+ u8 *mem = (u8 *) (budget->grabbing);
+ u32 olddma = budget->ttbp;
+ u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
+
+ /* nearest lower position divisible by 188 */
+ newdma -= newdma % 188;
+
+ if (newdma >= TS_BUFLEN)
+ return;
+
+ budget->ttbp = newdma;
+
+ if (budget->feeding1 == 0 || newdma == olddma)
+ return;
+
+#if 0
+ printk("vpeirq: %02x Event Counter 1 0x%04x\n",
+ mem[olddma],
+ saa7146_read(budget->dev, EC1R) & 0x3fff );
+#endif
+
+ if (newdma > olddma) { /* no wraparound, dump olddma..newdma */
+ dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188);
+ } else { /* wraparound, dump olddma..buflen and 0..newdma */
+ dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188);
+ dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188);
+ }
+}
static int av7110_register(struct av7110 *av7110)
{
int ret, i;
struct dvb_demux *dvbdemux = &av7110->demux;
+ struct dvb_demux *dvbdemux1 = &av7110->demux1;
dprintk(4, "%p\n", av7110);
@@ -1200,6 +1314,47 @@ static int av7110_register(struct av7110
dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx);
+ /* initialize software demux1 without frontend */
+ dvbdemux1->priv = (void *) av7110;
+
+ dvbdemux1->filternum = 256;
+ dvbdemux1->feednum = 256;
+ dvbdemux1->start_feed = budget_start_feed;
+ dvbdemux1->stop_feed = budget_stop_feed;
+ dvbdemux1->write_to_decoder = NULL;
+
+ dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING);
+
+ dvb_dmx_init(&av7110->demux1);
+
+ av7110->dmxdev1.filternum = 256;
+ av7110->dmxdev1.demux = &dvbdemux1->dmx;
+ av7110->dmxdev1.capabilities = 0;
+
+ dvb_dmxdev_init(&av7110->dmxdev1, av7110->dvb_adapter);
+
+#if 0
+ av7110->hw_frontend1.source = DMX_FRONTEND_0;
+ ret = dvbdemux1->dmx.add_frontend(&dvbdemux1->dmx, &av7110->hw_frontend1);
+ if (ret < 0)
+ return ret;
+#endif
+#if 0
+ av7110->mem_frontend1.source = DMX_MEMORY_FE;
+ ret = dvbdemux1->dmx.add_frontend(&dvbdemux1->dmx, &av7110->mem_frontend1);
+ if (ret < 0)
+ return ret;
+ ret = dvbdemux1->dmx.connect_frontend(&dvbdemux1->dmx, &av7110->hw_frontend1);
+ if (ret < 0)
+ return ret;
+#endif
+
+ dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx);
+ printk("additional demux registered\n");
+
+ /* end software demux1 */
+
return 0;
}
@@ -1945,7 +2100,9 @@ static void frontend_init(struct av7110
static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
{
struct av7110 *av7110 = NULL;
+ int length = TS_WIDTH * TS_HEIGHT;
int ret = 0;
+ int count = 0;
dprintk(4, "dev: %p\n", dev);
@@ -1989,20 +2146,152 @@ static int av7110_attach(struct saa7146_
ttpci_eeprom_parse_mac(&av7110->i2c_adap, av7110->dvb_adapter->proposed_mac);
- saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
+ if (NULL ==
+ (av7110->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &av7110->pt))) {
+ return -ENOMEM;
+ }
+
+ saa7146_write(dev, PCI_BT_V1, 0x1c1c101f);
saa7146_write(dev, BCS_CTRL, 0x80400040);
+ tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+
/* set dd1 stream a & b */
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
- saa7146_write(dev, DD1_INIT, 0x03000000);
+ saa7146_write(dev, DD1_INIT, 0x03000200);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+ saa7146_write(dev, BRS_CTRL, 0x60000000);
+ saa7146_write(dev, BASE_ODD3, 0);
+ saa7146_write(dev, BASE_EVEN3, 0);
+ saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
+ saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
+
+ saa7146_write(dev, PITCH3, TS_WIDTH);
+ saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
/* upload all */
saa7146_write(dev, MC2, 0x077c077c);
saa7146_write(dev, GPIO_CTRL, 0x000000);
+ tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+
+#define RPS_IRQ 1
+#if RPS_IRQ
+ // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
+ // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
+ // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
+ saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+ // set event counter 1 treshold to maximum allowed value (rEC p55)
+ saa7146_write(dev, ECT1R, 0x3fff );
+#endif
+
+/* New design (By Emard)
+** this rps1 code will copy internal HS event to GPIO3 pin.
+** GPIO3 is in budget-patch hardware connectd to port B VSYNC
+
+** HS is an internal event of 7146, accessible with RPS
+** and temporarily raised high every n lines
+** (n in defined in the RPS_THRESH1 counter threshold)
+** I think HS is raised high on the beginning of the n-th line
+** and remains high until this n-th line that triggered
+** it is completely received. When the receiption of n-th line
+** ends, HS is lowered.
+
+** To transmit data over DMA, 7146 needs changing state at
+** port B VSYNC pin. Any changing of port B VSYNC will
+** cause some DMA data transfer, with more or less packets loss.
+** It depends on the phase and frequency of VSYNC and
+** the way of 7146 is instructed to trigger on port B (defined
+** in DD1_INIT register, 3rd nibble from the right valid
+** numbers are 0-7, see datasheet)
+**
+** The correct triggering can minimize packet loss,
+** dvbtraffic should give this stable bandwidths:
+** 22k transponder = 33814 kbit/s
+** 27.5k transponder = 38045 kbit/s
+** by experiment it is found that the best results
+** (stable bandwidths and almost no packet loss)
+** are obtained using DD1_INIT triggering number 2
+** (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
+** and a VSYNC phase that occurs in the middle of DMA transfer
+** (about byte 188*512=96256 in the DMA window).
+**
+** Phase of HS is still not clear to me how to control,
+** It just happens to be so. It can be seen if one enables
+** RPS_IRQ and print Event Counter 1 in vpeirq(). Every
+** time RPS_INTERRUPT is called, the Event Counter 1 will
+** increment. That's how the 7146 is programmed to do event
+** counting in this budget-patch.c
+** I *think* HPS setting has something to do with the phase
+** of HS but I cant be 100% sure in that.
+
+** hardware debug note: a working budget card (including budget patch)
+** with vpeirq() interrupt setup in mode "0x90" (every 64K) will
+** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
+** and that means 3*25=75 Hz of interrupt freqency, as seen by
+** watch cat /proc/interrupts
+**
+** If this frequency is 3x lower (and data received in the DMA
+** buffer don't start with 0x47, but in the middle of packets,
+** whose lengths appear to be like 188 292 188 104 etc.
+** this means VSYNC line is not connected in the hardware.
+** (check soldering pcb and pins)
+** The same behaviour of missing VSYNC can be duplicated on budget
+** cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
+*/
+
+ // Setup RPS1 "program" (p35)
+ count = 0;
+
+
+ // Wait Source Line Counter Threshold (p36)
+ WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
+ // Set GPIO3=1 (p42)
+ WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
+ WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
+ WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+#if RPS_IRQ
+ // issue RPS1 interrupt
+ WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+#endif
+ // Wait reset Source Line Counter Threshold (p36)
+ WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
+ // Set GPIO3=0 (p42)
+ WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
+ WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
+ WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+#if RPS_IRQ
+ // issue RPS1 interrupt
+ WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+#endif
+ // Jump to begin of RPS program (p37)
+ WRITE_RPS1(cpu_to_le32(CMD_JUMP));
+ WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+
+ // Fix VSYNC level
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+ // Set RPS1 Address register to point to RPS code (r108 p42)
+ saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+ // Set Source Line Counter Threshold, using BRS (rCC p43)
+ // It generates HS event every TS_HEIGHT lines
+ // this is related to TS_WIDTH set in register
+ // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
+ // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
+ //,then RPS_THRESH1
+ // should be set to trigger every TS_HEIGHT (512) lines.
+ //
+ saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
+
+ // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
+ // Enable RPS1 (rFC p33)
+ saa7146_write(dev, MC1, (MASK_13 | MASK_29));
+
+
+
tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
+ tasklet_init (&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+ spin_lock_init(&av7110->feedlock1);
sema_init(&av7110->pid_mutex, 1);
@@ -2115,6 +2404,9 @@ static int av7110_detach (struct saa7146
return 0;
}
+ tasklet_kill(&av7110->vpe_tasklet);
+ saa7146_pgtable_free(saa->pci, &av7110->pt);
+
av7110_exit_v4l(av7110);
av7110->arm_rmmod = 1;
@@ -2187,6 +2479,11 @@ static void av7110_irq(struct saa7146_de
//printk("av7110_irq: GPIO\n");
tasklet_schedule(&av7110->gpio_tasklet);
}
+
+ if (*isr & MASK_10)
+ {
+ tasklet_schedule(&av7110->vpe_tasklet);
+ }
}
@@ -2238,7 +2535,7 @@ static struct saa7146_extension av7110_e
.attach = av7110_attach,
.detach = av7110_detach,
- .irq_mask = MASK_19 | MASK_03,
+ .irq_mask = MASK_19 | MASK_03 | MASK_10,
.irq_func = av7110_irq,
};
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: av7110.c~
diff -pur dvb-kernel.orig/linux/drivers/media/dvb/ttpci/av7110.h dvb-kernel/linux/drivers/media/dvb/ttpci/av7110.h
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/av7110.h 2005-01-02 18:44:41.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/av7110.h 2005-01-02 21:43:11.000000000 +0100
@@ -75,7 +75,7 @@ struct av7110 {
/* devices */
struct dvb_device dvb_dev;
- struct dvb_net dvb_net;
+ struct dvb_net dvb_net, dvb_net1;
struct video_device *v4l_dev;
struct video_device *vbi_dev;
@@ -152,12 +152,19 @@ struct av7110 {
ca_slot_info_t ci_slot[2];
int vidmode;
- struct dmxdev dmxdev;
- struct dvb_demux demux;
-
- struct dmx_frontend hw_frontend;
- struct dmx_frontend mem_frontend;
-
+ struct dmxdev dmxdev, dmxdev1;
+ struct dvb_demux demux, demux1;
+ spinlock_t feedlock1; /* for budget mode demux1 */
+ int feeding1;
+ u8 tsf;
+ u32 ttbp;
+ unsigned char *grabbing;
+ struct saa7146_pgtable pt;
+ struct tasklet_struct vpe_tasklet;
+
+ struct dmx_frontend hw_frontend, hw_frontend1;
+ struct dmx_frontend mem_frontend, mem_frontend1;
+
int fe_synced;
struct semaphore pid_mutex;
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: av7110.h~
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: budget-core.c~
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: budget-core.h
Only in dvb-kernel/linux/drivers/media/dvb/ttpci: budget-core.h~
Home |
Main Index |
Thread Index