Hi,

I tried my best to take all your suggestions into account and rewrote the filters for the skystar2 cards. Especially (based on the valueable info given by Augusto) there is now a different handling for FC IIb and FC III based cards, the additional 32 PID filters should work. Also I tried my best to handle the 0x2000/open_whole_bandwidth issue in a transparent way.
As usual I cannot test my code right now ;), so it would be great if anybody could have a look, esp. if you own a FC IIb or FC III (which I don't have).


Anyhow, here comes the patch.

Niklas
Index: skystar2.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/b2c2/skystar2.c,v
retrieving revision 1.17
diff -p -u -r1.17 skystar2.c
--- skystar2.c  1 Dec 2003 08:28:49 -0000       1.17
+++ skystar2.c  2 Dec 2003 10:58:58 -0000
@@ -9,6 +9,9 @@
  *     
  * IMP: Converted to Linux coding style
  *      Roberto Ragusa, r.ragusa at libero.it
+ *
+ * Added hardware filtering support, 
+ *     Niklas Peinecke, peinecke at gdv.uni-hannover.de
  *     
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -95,7 +98,10 @@ struct adapter {
 
        spinlock_t lock;
 
-       u16 pids[0x27];
+       u16 pids[38];
+       u16 pid_list[256];
+       u16 pid_count;
+       u8 wb_open;
        u32 mac_filter;
 };
 
@@ -928,6 +934,29 @@ static char eeprom_set_mac_addr(struct a
 */
 
 /* PID filter */
+
+/* every flexcop has 6 "lower" hw PID filters     */
+/* these are enabled by setting bits 0-5 of 0x208 */
+/* we do not check for id>5 here!                 */
+static void filter_enable_hw_filter(struct adapter *adapter,u8 id,u8 op)
+{
+       u32 mask=( 0x00000001 << id );
+       if (op == 0) write_reg_op(adapter, 0x208, 2, ~mask, 0);
+       else write_reg_op(adapter, 0x208, 1, 0, mask);
+}
+
+/* this sets the PID that should pass the specified filter */
+static void pid_set_hw_pid(struct adapter * adapter,u8 id,u32 pid)
+{
+       u32 adr=0x300+((id&6)<<1);
+       
+       if((id&1)==0) write_reg_op(adapter,adr,3,0xffff8000,pid&0x1fff);
+       else write_reg_op(adapter,adr,3,0x8000ffff,(pid&0x1fff)<<16);
+}
+
+
+
+/*
 static void filter_enable_stream1_filter(struct adapter *adapter, u32 op)
 {
        dprintk("%s: op=%x\n", __FUNCTION__, op);
@@ -980,7 +1009,7 @@ static void filter_enable_pmt_filter(str
        }
 }
 
-static void filter_enable_emm_fFilter(struct adapter *adapter, u32 op)
+static void filter_enable_emm_filter(struct adapter *adapter, u32 op)
 {
        dprintk("%s: op=%x\n", __FUNCTION__, op);
 
@@ -1004,7 +1033,7 @@ static void filter_enable_ecm_filter(str
 
                write_reg_op(adapter, 0x208, 1, 0, 0x00000020);
        }
-}
+}*/
 
 /*
 static void filter_enable_null_filter(struct adapter *adapter, u32 op)
@@ -1046,6 +1075,27 @@ static void ctrl_enable_mac(struct adapt
        }
 }
 
+/* NP experimental code */
+
+/* select data filter nr. id for setup */
+static void filter_select_data_filter(struct adapter *adapter,u8 id)
+{
+       write_reg_op(adapter,0x310,3,0xffffffe0,id&0x1f);
+}
+
+/* enable data filter; 0: disable, 1: enable */
+static void filter_enable_data_filter(struct adapter *adapter,u8 op)
+{
+       if(op==0) write_reg_op(adapter,0x314,2,0xffff9fff,0);
+       else write_reg_op(adapter,0x314,3,0xffff9fff,0x00004000);
+}
+
+/* set PID for data filter */
+static void pid_set_data_pid(struct adapter *adapter,u32 pid)
+{
+       write_reg_op(adapter,0x314,3,0xffffe000,pid & 0x1fff);
+}
+
 static int ca_set_mac_dst_addr_filter(struct adapter *adapter, u8 * mac)
 {
        u32 tmp1, tmp2;
@@ -1086,12 +1136,23 @@ static void check_null_filter_enable(str
 }
 */
 
-static void init_pids_info(struct adapter *adapter)
+static void init_pids(struct adapter *adapter)
 {
        int i;
 
        for (i = 0; i < 0x27; i++)
                adapter->pids[i] = 0x1FFF;
+       adapter->pid_count=0;
+       adapter->wb_open=0;
+       
+       pid_set_group_pid(adapter, 0);
+       pid_set_group_mask(adapter, 0x1FE0);
+       pid_set_hw_pid(adapter,0,0x1FFF);
+       pid_set_hw_pid(adapter,1,0x1FFF);
+       pid_set_hw_pid(adapter,2,0x1FFF);
+       pid_set_hw_pid(adapter,3,0x1FFF);
+       pid_set_hw_pid(adapter,4,0x1FFF);
+       pid_set_hw_pid(adapter,5,0x1FFF);
 }
 
 static int check_pid(struct adapter *adapter, u16 pid)
@@ -1100,11 +1161,11 @@ static int check_pid(struct adapter *ada
 
        if (pid == 0x1FFF)
                return 0;
-        
-       for (i = 0; i < 0x27; i++) {
-               if (adapter->pids[i] == pid || adapter->pids[i] == 0x2000)
-                       return 1;
-       }
+   
+       if(pid==0x2000 && adapter->wb_open!=0) return 1; // do we need this?
+       
+       for(i=0; i<adapter->pid_count; i++)
+               if(adapter->pid_list[i]==pid) return 1;
 
        return 0;
 }
@@ -1137,90 +1198,6 @@ static void pid_set_group_mask(struct ad
 /*     return value; */
 }
 
-static void pid_set_stream1_pid(struct adapter * adapter, u32 pid)
-{
-       u32 value;
-
-       dprintk("%s: pid=%x\n", __FUNCTION__, pid);
-
-       value = (pid & 0x3FFF) | (read_reg_dw(adapter, 0x300) & 0xFFFFC000);
-
-       write_reg_dw(adapter, 0x300, value);
-
-       /* return value is never used? */
-/*     return value; */
-}
-
-static void pid_set_stream2_pid(struct adapter * adapter, u32 pid)
-{
-       u32 value;
-
-       dprintk("%s: pid=%x\n", __FUNCTION__, pid);
-
-       value = ((pid & 0x3FFF) << 0x10) | (read_reg_dw(adapter, 0x300) & 0xFFFF);
-
-       write_reg_dw(adapter, 0x300, value);
-
-       /* return value is never used? */
-/*     return value; */
-}
-
-static void pid_set_pcr_pid(struct adapter * adapter, u32 pid)
-{
-       u32 value;
-
-       dprintk("%s: pid=%x\n", __FUNCTION__, pid);
-
-       value = (pid & 0x3FFF) | (read_reg_dw(adapter, 0x304) & 0xFFFFC000);
-
-       write_reg_dw(adapter, 0x304, value);
-
-       /* return value is never used? */
-/*     return value; */
-}
-
-static void pid_set_pmt_pid(struct adapter * adapter, u32 pid)
-{
-       u32 value;
-
-       dprintk("%s: pid=%x\n", __FUNCTION__, pid);
-
-       value = ((pid & 0x3FFF) << 0x10) | (read_reg_dw(adapter, 0x304) & 0x3FFF);
-
-       write_reg_dw(adapter, 0x304, value);
-
-       /* return value is never used? */
-/*     return value; */
-}
-
-static void pid_set_emm_pid(struct adapter * adapter, u32 pid)
-{
-       u32 value;
-
-       dprintk("%s: pid=%x\n", __FUNCTION__, pid);
-
-       value = (pid & 0xFFFF) | (read_reg_dw(adapter, 0x308) & 0xFFFF0000);
-
-       write_reg_dw(adapter, 0x308, value);
-
-       /* return value is never used? */
-/*     return value; */
-}
-
-static void pid_set_ecm_pid(struct adapter * adapter, u32 pid)
-{
-       u32 value;
-
-       dprintk("%s: pid=%x\n", __FUNCTION__, pid);
-
-       value = (pid << 0x10) | (read_reg_dw(adapter, 0x308) & 0xFFFF);
-
-       write_reg_dw(adapter, 0x308, value);
-
-       /* return value is never used? */
-/*     return value; */
-}
-
 static int pid_get_stream1_pid(struct adapter * adapter)
 {
        return read_reg_dw(adapter, 0x300) & 0x00001FFF;
@@ -1279,7 +1256,7 @@ static void reset_hardware_pid_filter(st
        filter_enable_ecm_filter(adapter, 0);
 
        pid_set_emm_pid(adapter, 0x1FFF);
-       filter_enable_emm_fFilter(adapter, 0);
+       filter_enable_emm_filter(adapter, 0);
 }
 */
 
@@ -1292,175 +1269,177 @@ static void open_whole_bandwidth(struct 
        pid_set_group_mask(adapter, 0);
 
        filter_enable_mask_filter(adapter, 1);
-
 }
 
-static int add_hw_pid(struct adapter *adapter, u32 pid)
+static void close_whole_bandwidth(struct adapter *adapter)
 {
-       dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
-       if (pid <= 0x1F)
-               return 1;
-
-       if ((pid_get_group_mask(adapter) == 0) && (pid_get_group_pid(adapter) == 0))
-               return 0;
-
-       if (pid_get_stream1_pid(adapter) == 0x1FFF) {
-               pid_set_stream1_pid(adapter, pid & 0xFFFF);
-
-               filter_enable_stream1_filter(adapter, 1);
-
-               return 1;
-       }
-
-       if (pid_get_stream2_pid(adapter) == 0x1FFF) {
-               pid_set_stream2_pid(adapter, (pid & 0xFFFF));
-
-               filter_enable_stream2_filter(adapter, 1);
-
-               return 1;
-       }
-
-       if (pid_get_pcr_pid(adapter) == 0x1FFF) {
-               pid_set_pcr_pid(adapter, (pid & 0xFFFF));
-
-               filter_enable_pcr_filter(adapter, 1);
-
-               return 1;
-       }
-
-       if ((pid_get_pmt_pid(adapter) & 0x1FFF) == 0x1FFF) {
-               pid_set_pmt_pid(adapter, (pid & 0xFFFF));
-
-               filter_enable_pmt_filter(adapter, 1);
-
-               return 1;
-       }
-
-       if ((pid_get_emm_pid(adapter) & 0x1FFF) == 0x1FFF) {
-               pid_set_emm_pid(adapter, (pid & 0xFFFF));
-
-               filter_enable_emm_fFilter(adapter, 1);
-
-               return 1;
-       }
+        dprintk("%s:\n", __FUNCTION__);
+       
+       pid_set_group_pid(adapter, 0);
 
-       if ((pid_get_ecm_pid(adapter) & 0x1FFF) == 0x1FFF) {
-               pid_set_ecm_pid(adapter, (pid & 0xFFFF));
+       pid_set_group_mask(adapter, 0x1fe0);
 
-               filter_enable_ecm_filter(adapter, 1);
+       filter_enable_mask_filter(adapter, 1);
+}
 
-               return 1;
+/* this tries to add the specified PID to be let through the
+   hw filters. return 1 on success.
+       if this cannot be done (all filter in use), returns -1
+       for PID <= 0x1f there is always success reported, since
+       these are let through by the group filters anyway. */
+static int add_hw_pid(struct adapter *adapter, u32 pid)
+{
+       int num,i;
+       
+       if(pid<=0x1f) return 1;
+       
+       if(adapter->b2c2_revision==0xc0 || adapter->b2c2_revision==0xc3)
+               num=38;   // FlexCop IIb & III have 6+32 hw filters    
+       else num=6;  // FlexCop II has 6 hw filters, every other should have at least 6
+       
+       for(i=0; i<num; i++)
+       {
+               if (adapter->pids[i] == 0x1fff) // find a free pid slot
+               {
+                       adapter->pids[i]=pid;
+                       if(i<6)
+                       {
+                               pid_set_hw_pid(adapter,i,pid);
+                               filter_enable_hw_filter(adapter,i,1);
+                               return 1;
+                       }
+                       else
+                       {
+                               filter_select_data_filter(adapter,i-6);
+                               pid_set_data_pid(adapter,pid);
+                               filter_enable_data_filter(adapter,1);
+                               return 1;
+                       }
+               }
        }
-
        return -1;
 }
 
 static int remove_hw_pid(struct adapter *adapter, u32 pid)
 {
-       dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
-       if (pid <= 0x1F)
-               return 1;
-
-       if (pid_get_stream1_pid(adapter) == pid) {
-               pid_set_stream1_pid(adapter, 0x1FFF);
-
-               return 1;
-       }
-
-       if (pid_get_stream2_pid(adapter) == pid) {
-               pid_set_stream2_pid(adapter, 0x1FFF);
-
-               filter_enable_stream2_filter(adapter, 0);
-
-               return 1;
-       }
-
-       if (pid_get_pcr_pid(adapter) == pid) {
-               pid_set_pcr_pid(adapter, 0x1FFF);
-
-               filter_enable_pcr_filter(adapter, 0);
-
-               return 1;
-       }
-
-       if (pid_get_pmt_pid(adapter) == pid) {
-               pid_set_pmt_pid(adapter, 0x1FFF);
-
-               filter_enable_pmt_filter(adapter, 0);
-
-               return 1;
-       }
-
-       if (pid_get_emm_pid(adapter) == pid) {
-               pid_set_emm_pid(adapter, 0x1FFF);
-
-               filter_enable_emm_fFilter(adapter, 0);
-
-               return 1;
-       }
-
-       if (pid_get_ecm_pid(adapter) == pid) {
-               pid_set_ecm_pid(adapter, 0x1FFF);
-
-               filter_enable_ecm_filter(adapter, 0);
-
-               return 1;
+       int num,i;
+       
+       if(pid<=0x1f) return 1;
+       
+       if(adapter->b2c2_revision==0xc0 || adapter->b2c2_revision==0xc3)
+               num=38;   // FlexCop IIb & III have 6+32 hw filters    
+       else num=6;  // FlexCop II has 6 hw filters, every other should have at least 6
+       
+       for(i=0; i<num; i++)
+       {
+               if (adapter->pids[i] == pid)    // find the pid slot
+               {
+                       adapter->pids[i]=0x1fff;
+                       if(i<6)
+                       {
+                               pid_set_hw_pid(adapter,i,pid);
+                               filter_enable_hw_filter(adapter,i,0);
+                               return 1;
+                       }
+                       else
+                       {
+                               filter_select_data_filter(adapter,i-6);
+                               pid_set_data_pid(adapter,pid);
+                               filter_enable_data_filter(adapter,0);
+                               return 1;
+                       }
+               }
        }
-
        return -1;
 }
 
-static int add_pid(struct adapter *adapter, u32 pid)
+/* Adds a PID to the filters.
+   If there are no more hw filters available, open the whole
+       ts stream to pass by.
+       Adding a pid more than once has no effect.
+       If pid==0x2000, open whole ts stream also.
+       Returns 1 on success, -1 on error */
+static int add_pid(struct adapter *adapter,u32 pid)
 {
        int i;
-
+       
        dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
-       if (pid > 0x1FFE && pid != 0x2000)
-               return -1;
-
-       if (check_pid(adapter, pid) == 1)
+       
+       if(pid==0x2000)
+       {
+               open_whole_bandwidth(adapter);
+               adapter->wb_opened|=1;
+               // 1 is for opened by 0x2000
                return 1;
-
-       for (i = 0; i < 0x27; i++) {
-               if (adapter->pids[i] == 0x1FFF) // find free pid filter
-               {
-                       adapter->pids[i] = pid;
-
-                       if (pid == 0x2000 || add_hw_pid(adapter, pid) < 0)
-                               open_whole_bandwidth(adapter);
-
-                       return 1;
-               }
        }
-
-       return -1;
+       
+       if (pid > 0x1ffe) return -1;
+       
+       // check if the pid is already present
+       for(i=0; i<adapter->pid_count; i++)
+               if(adapter->pid_list[i]==pid) return 1;
+       
+       if(adapter->pid_count==256) return -1; // no more pids can be added
+       adapter->pid_list[pid_count]=pid;      // register pid
+       adapter->pid_count++;
+       
+       // setup a filter for the pid
+       // if there are no filters left, let the whole ts pass
+       if(add_hw_pid(adapter,pid)==-1)
+       {
+               open_whole_bandwidth(adapter);
+               adapter->wb_opened|=2;
+               // 2 is for opened by overflow
+       }
+       
+       return 1;
 }
 
+/* Removes a PID from the filters. */
 static int remove_pid(struct adapter *adapter, u32 pid)
 {
-       u32 i;
-
-       dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
-       if (pid > 0x1FFE)
-               return -1;
-
-       for (i = 0; i < 0x27; i++) {
-               if (adapter->pids[i] == pid) {
-                       adapter->pids[i] = 0x1FFF;
-
-                       remove_hw_pid(adapter, pid);
-
-                       return 1;
+       int i,j,num;    
+       
+       if(pid==0x2000)
+       {
+               adapter->wb_opened&=2;
+               if(adapter->wb_opened==0) close_whole_bandwidth(adapter);
+               return 1;
+       }
+       
+       if (pid > 0x1ffe && pid != 0x2000) return -1;
+       
+       // check if the pid is present
+       for(i=0; i<adapter->pid_count; i++)
+               if(adapter->pid_list[i]==pid)
+       {
+               // remove from the list
+               adapter->pid_count--;
+               for(j=i; j<adapter->pid_count; j++)
+               {
+                       adapter->pid_list[j]=adapter->pid_list[j+1];
+               }       
+               
+               // close filter
+               remove_hw_pid(adapter,pid);
+               
+               // now take care to reverse the effect of open_whole_bandwidth
+               if(adapter->b2c2_revision==0xc0 || adapter->b2c2_revision==0xc3)
+                       num=38;   // FlexCop IIb & III have 6+32 hw filters    
+               else num=6;  // FlexCop II has 6 hw filters, every other should have 
at least 6
+               if(adapter->pid_count<num)
+               {
+                       adapter->wb_opened&=1;
+                       if(adapter->wb_opened==0) close_whole_bandwidth(adapter);
                }
+               
+               return 1;
        }
-
+       
        return -1;
 }
 
+
 /* dma & irq */
 static void ctrl_enable_smc(struct adapter *adapter, u32 op)
 {
@@ -2075,16 +2054,7 @@ static int driver_initialize(struct pci_
        write_reg_dw(adapter, 0x210, 0xB2FF);
        write_reg_dw(adapter, 0x208, 0x40);
 
-       init_pids_info(adapter);
-
-       pid_set_group_pid(adapter, 0);
-       pid_set_group_mask(adapter, 0x1FE0);
-       pid_set_stream1_pid(adapter, 0x1FFF);
-       pid_set_stream2_pid(adapter, 0x1FFF);
-       pid_set_pmt_pid(adapter, 0x1FFF);
-       pid_set_pcr_pid(adapter, 0x1FFF);
-       pid_set_ecm_pid(adapter, 0x1FFF);
-       pid_set_emm_pid(adapter, 0x1FFF);
+       init_pids(adapter);
 
        init_dma_queue(adapter);
 

Reply via email to