Skip to contentSkip to conversation

LinuxTV.org DVB update

PATCH In review Michael Hunold 2 participants 11 messages Apr 26, 2004

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover LinuxTV.org DVB update

Hello Linus, Andrew,

I'm sending you a set of 9 patches that sync the LinuxTV.org CVS with latest linux-2.6.5.

I'm glad that I can announce that we have recently forked off our 2.6 development tree, so we are really looking forward to implement
- proper kobject/sysfs support
- proper firmware loading for frontend drivers
- removal of dvb-i2c and use of kernel i2c instead
- other interesting 2.6 specific things

This is the last patchset that rides the dead "2.4 compatiblity" horse.

As usual, detailed informations about what changed can be found at the top of each file.

Please apply!

CU
Michael.

#1 lore raw

PATCH 1/9 V4L: Update the saa7146 driver

- [DVB] saa7146 driver updates:
- remove bogus v_calc and h_calc parameters, which can be easily retrieved from other values
- add class parameter to i2c initialization
- let resource handling provide more useful informations
- sanitize overlay/capture locking

drivers/media/common/saa7146_fops.c +5 -7
diff -urawBN xx-linux-2.6.5/drivers/media/common/saa7146_fops.c linux-2.6.5-patched/drivers/media/common/saa7146_fops.c
@@ -10,14 +10,14 @@
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_vv *vv = dev->vv_data;
 
-	if (fh->resources & bit)
+	if (fh->resources & bit) {
+		DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources));
 		/* have it already allocated */
 		return 1;
+	}
 
 	/* is it free? */
-	DEB_D(("getting lock...\n"));
 	down(&dev->lock);
-	DEB_D(("got lock\n"));
 	if (vv->resources & bit) {
 		DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
 		/* no, someone else uses it */
@@ -27,7 +27,7 @@
 	/* it's free, grab it */
 	fh->resources  |= bit;
 	vv->resources |= bit;
-	DEB_D(("res: get %d\n",bit));
+	DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
 	up(&dev->lock);
 	return 1;
 }
@@ -51,12 +51,10 @@
 	if ((fh->resources & bits) != bits)
 		BUG();
 
-	DEB_D(("getting lock...\n"));
 	down(&dev->lock);
-	DEB_D(("got lock\n"));
 	fh->resources  &= ~bits;
 	vv->resources &= ~bits;
-	DEB_D(("res: put %d\n",bits));
+	DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
 	up(&dev->lock);
 }
 
drivers/media/common/saa7146_hlp.c +2 -2
diff -urawBN xx-linux-2.6.5/drivers/media/common/saa7146_hlp.c linux-2.6.5-patched/drivers/media/common/saa7146_hlp.c
@@ -536,13 +536,13 @@
 	/* set vertical scale */
 	hps_v_scale = 0; /* all bits get set by the function-call */
 	hps_v_gain  = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/ 
-	calculate_v_scale_registers(dev, field, vv->standard->v_calc, height, &hps_v_scale, &hps_v_gain);
+	calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain);
 
 	/* set horizontal scale */
 	hps_ctrl 	= 0;
 	hps_h_prescale	= 0; /* all bits get set in the function */
 	hps_h_scale	= 0;
-	calculate_h_scale_registers(dev, vv->standard->h_calc, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
+	calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
 
 	/* set hyo and hxo */
 	calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl);
drivers/media/common/saa7146_i2c.c +2 -5
diff -urawBN xx-linux-2.6.5/drivers/media/common/saa7146_i2c.c linux-2.6.5-patched/drivers/media/common/saa7146_i2c.c
@@ -400,7 +400,7 @@
 	.functionality	= saa7146_i2c_func,
 };
 
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
+int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, unsigned int class, u32 bitrate)
 {
 	DEB_EE(("bitrate: 0x%08x\n",bitrate));
 	
@@ -417,16 +417,13 @@
 		i2c_adapter->data = dev;
 #else
 		i2c_set_adapdata(i2c_adapter,dev);
+		i2c_adapter->class = class;
 #endif
 		i2c_adapter->algo	   = &saa7146_algo;
 		i2c_adapter->algo_data     = NULL;
 		i2c_adapter->id 	   = I2C_ALGO_SAA7146;
 		i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
 		i2c_adapter->retries = SAA7146_I2C_RETRIES;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#else
-		i2c_adapter->class = I2C_ADAP_CLASS_TV_ANALOG;
-#endif
 	}
 	
 	return 0;
drivers/media/common/saa7146_video.c +169 -166

609 lines not on this page · raw message

include/media/saa7146.h +1 -1
diff -urawBN xx-linux-2.6.5/include/media/saa7146.h linux-2.6.5-patched/include/media/saa7146.h
@@ -154,7 +166,7 @@
 };
 
 /* from saa7146_i2c.c */
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
+int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, unsigned int class, u32 bitrate);
 int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num,  int retries);
 
 /* from saa7146_core.c */
include/media/saa7146_vv.h +7 -3
diff -urawBN xx-linux-2.6.5/include/media/saa7146_vv.h linux-2.6.5-patched/include/media/saa7146_vv.h
@@ -44,11 +44,9 @@
 
 	int v_offset;	/* number of lines of vertical offset before processing */
 	int v_field;	/* number of lines in a field for HPS to process */
-	int v_calc;	/* number of vertical active lines */
 	
 	int h_offset;	/* horizontal offset of processing window */
 	int h_pixels;	/* number of horizontal pixels to process */
-	int h_calc;	/* number of horizontal active pixels */
 	
 	int v_max_out;
 	int h_max_out;
@@ -104,6 +102,9 @@
 	unsigned int resources;	/* resource management for device open */
 };
 
+#define STATUS_OVERLAY	0x01
+#define STATUS_CAPTURE	0x02
+
 struct saa7146_vv
 {
 	int vbi_minor;
@@ -117,14 +118,17 @@
 
 	int video_minor;
 
+	int				video_status;
+	struct saa7146_fh		*video_fh;
+
 	/* video overlay */
 	struct v4l2_framebuffer		ov_fb;
 	struct saa7146_format		*ov_fmt;
 	struct saa7146_overlay		*ov_data;
+	struct saa7146_fh		*ov_suspend;
 
 	/* video capture */
 	struct saa7146_dmaqueue		video_q;
-	struct saa7146_fh		*streaming;
 	enum v4l2_field			last_field;
 
 	/* common: fixme? shouldn't this be in saa7146_fh?
#2 lore raw

PATCH 2/9 DVB: Documentation and Kconfig updazes

- [DVB] misc. documentation updates, KConfig help file updates
- [DVB] make Twinhan driver depend on bt8xx

drivers/media/dvb/frontends/Kconfig +1 -1
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/Kconfig linux-2.6.5-patched/drivers/media/dvb/frontends/Kconfig
@@ -3,7 +3,7 @@
 
 config DVB_TWINHAN_DST
 	tristate "TWINHAN DST based DVB-S frontend (QPSK)"
-	depends on DVB_CORE
+	depends on DVB_CORE && DVB_BT8XX
 	help
 	  Used in such cards as the VP-1020/1030, Twinhan DST,
 	  VVmer TV@SAT. Say Y when you want to support frontends 
Documentation/dvb/cards.txt +2 -0
diff -urawBN xx-linux-2.6.5/Documentation/dvb/cards.txt linux-2.6.5-patched/Documentation/dvb/cards.txt
@@ -50,6 +50,8 @@
     - Technotrend Budget / Hauppauge WinTV-Nova PCI Cards
     - SATELCO Multimedia PCI
     - KNC1 DVB-S
+    - Typhoon DVB-S budget
+    - Fujitsu-Siemens Activy DVB-S budget card
 
 o Cards based on the B2C2 Inc. FlexCopII/IIb/III:
   - Technisat SkyStar2 PCI DVB card revision 2.3, 2.6B, 2.6C
Documentation/dvb/contributors.txt +8 -0
diff -urawBN xx-linux-2.6.5/Documentation/dvb/contributors.txt linux-2.6.5-patched/Documentation/dvb/contributors.txt
@@ -62,5 +62,13 @@
   for his work on calculating and checking the crc's for the
   TechnoTrend/Hauppauge DEC driver firmware
 
+Michael Dreher <[email protected]>
+Andreas 'randy' Weinberger
+  for the support of the Fujitsu-Siemens Activy budget DVB-S
+
+Kenneth Aafl�y <[email protected]>
+  for adding support for Typhoon DVB-S budget card
+
+
 (If you think you should be in this list, but you are not, drop a
  line to the DVB mailing list)
Documentation/dvb/faq.txt +5 -0
diff -urawBN xx-linux-2.6.5/Documentation/dvb/faq.txt linux-2.6.5-patched/Documentation/dvb/faq.txt
@@ -94,6 +94,11 @@
 		MythTV - analog TV PVR, but now with DVB support, too
 		(with software MPEG decode)
 
+	http://dvbsnoop.sourceforge.net/
+		DVB sniffer program to monitor, analyze, debug, dump
+		or view dvb/mpeg/dsm-cc/mhp stream information (TS,
+		PES, SECTION)
+
 4. Can't get a signal tuned correctly
 
 	If you are using a Technotrend/Hauppauge DVB-C card *without* analog
drivers/media/dvb/Kconfig +2 -3
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/Kconfig linux-2.6.5-patched/drivers/media/dvb/Kconfig
@@ -18,12 +18,11 @@
 	  Please report problems regarding this driver to the LinuxDVB 
 	  mailing list.
 
-	  You might want add the following lines to your /etc/modprobe.conf:
+	  You might want add the following lines to your /etc/modules.conf:
 	  	
 	  	alias char-major-250 dvb
 	  	alias dvb dvb-ttpci
-	  	install dvb-ttpci /sbin/modprobe --first-time -i dvb-ttpci && \
-			/sbin/modprobe -a alps_bsru6 alps_bsrv2 \
+	  	below dvb-ttpci alps_bsru6 alps_bsrv2 \
 	  			grundig_29504-401 grundig_29504-491 \
 	  			ves1820
 
#3 lore raw

PATCH 3/9 DVB: Update DVB budget drivers

- [DVB] budget-av: patch by Kenneth Aafl�y to add support for Typhoon DVB-S budget card
- [DVB] budget.c: support for Fujitsu-Siemens Activy Card
- [DVB] budget-ci: add preliminary CI support

drivers/media/dvb/ttpci/budget-av.c +17 -16
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/ttpci/budget-av.c linux-2.6.5-patched/drivers/media/dvb/ttpci/budget-av.c
@@ -39,6 +39,7 @@
 	struct budget budget;
 	struct video_device vd;
 	int cur_input;
+	int has_saa7113;
 };
 
 /****************************************************************************
@@ -149,6 +150,9 @@
 {
 	struct budget *budget = &budget_av->budget;
 
+	if ( 1 != budget_av->has_saa7113 )
+		return -ENODEV;
+
 	if (input == 1) {
 		i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc7);
 		i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x80);
@@ -170,11 +174,13 @@
 
 	DEB_EE(("dev: %p\n",dev));
 
+	if ( 1 == budget_av->has_saa7113 ) {
 	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
 
 	dvb_delay(200);
 
 	saa7146_unregister_device (&budget_av->vd, dev);
+	}
 
 	err = ttpci_budget_deinit (&budget_av->budget);
 
@@ -221,11 +227,8 @@
 	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
 	dvb_delay(500);
 
-	if ((err = saa7113_init (budget_av))) {
-		/* fixme: proper cleanup here */
-		ERR(("cannot init saa7113.\n"));
-		return err;
-	}
+	if ( 0 == saa7113_init(budget_av) ) {
+		budget_av->has_saa7113 = 1;
 
 	if ( 0 != saa7146_vv_init(dev,&vv_data)) {
 		/* fixme: proper cleanup here */
@@ -246,14 +249,12 @@
 					SAA7146_HPS_SYNC_PORT_A);
 
 	saa7113_setinput (budget_av, 0);
+	} else {
+		budget_av->has_saa7113 = 0;
 
-	/* what is this? since we don't support open()/close()
-	   notifications, we simply put this into the release handler... */
-/*
 	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout (20);
-*/
+	}
+
 	/* fixme: find some sane values here... */
 	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
 
@@ -333,13 +334,13 @@
 static struct saa7146_standard standard[] = {
 	{
 		.name	= "PAL", 	.id	= V4L2_STD_PAL,
-		.v_offset	= 0x17,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 0x14,	.h_pixels 	= 680,	.h_calc		= 680+1,
-		.v_max_out	= 576,	.h_max_out	= 768,
+		.v_offset	= 0x17,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 680,  	      
+		.v_max_out	= 576,	.h_max_out	= 768
 	}, {
 		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
-		.v_offset	= 0x16,	.v_field 	= 240,	.v_calc		= 480,
-		.h_offset	= 0x06,	.h_pixels 	= 708,	.h_calc		= 708+1,
+		.v_offset	= 0x16,	.v_field 	= 240,
+		.h_offset	= 0x06,	.h_pixels 	= 708,
 		.v_max_out	= 480,	.h_max_out	= 640,
 	}
 };
drivers/media/dvb/ttpci/budget.c +58 -0

94 lines not on this page · raw message

drivers/media/dvb/ttpci/budget-ci.c +295 -10

416 lines not on this page · raw message

drivers/media/dvb/ttpci/budget-core.c +112 -8

192 lines not on this page · raw message

drivers/media/dvb/ttpci/budget.h +9 -0
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/ttpci/budget.h linux-2.6.5-patched/drivers/media/dvb/ttpci/budget.h
@@ -46,10 +46,15 @@
         int                     fe_synced; 
         struct semaphore        pid_mutex;
 
+	int                     ci_present;
+        int                     video_port;
+
         u8 tsf;
         u32 ttbp;
         int feeding;
 
+	spinlock_t feedlock;
+
         struct dvb_adapter       *dvb_adapter;
 	void			 *priv;
 };
@@ -73,13 +78,17 @@
 #define BUDGET_TT_HW_DISEQC	   1
 #define BUDGET_KNC1		   2
 #define BUDGET_PATCH		   3
+#define BUDGET_FS_ACTIVY	   4
 
+#define BUDGET_VIDEO_PORTA         0
+#define BUDGET_VIDEO_PORTB         1
 
 extern int ttpci_budget_init (struct budget *budget,
 			      struct saa7146_dev* dev,
 			      struct saa7146_pci_extension_data *info);
 extern int ttpci_budget_deinit (struct budget *budget);
 extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr);
+extern void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port);
 
 #endif
 
#4 lore raw

PATCH 4/9 DVB: Add EN50221 cam support to dvb-core

- [DVB] add generic functions for EN50221 CAM interfaces

drivers/media/dvb/dvb-core/dvb_ca_en50221.c +1628 -0
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/dvb-core/dvb_ca_en50221.c linux-2.6.5-patched/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -0,0 +1,1628 @@
+/*
+ * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
+ *
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * Parts of this file were based on sources as follows:
+ *
+ * Copyright (C) 2003 Ralph Metzler <[email protected]>
+ *
+ * based on code:
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <asm/semaphore.h>
+#include <asm/atomic.h>
+
+#include "dvb_ca_en50221.h"
+#include "dvb_functions.h"
+#include "dvb_ringbuffer.h"
+
+static int dvb_ca_en50221_debug = 0;
+#define dprintk if (dvb_ca_en50221_debug) printk
+
+#define INIT_TIMEOUT_SECS 5
+
+#define HOST_LINK_BUF_SIZE 0x200
+
+#define RX_BUFFER_SIZE 65535
+
+#define MAX_RX_PACKETS_PER_ITERATION 10
+
+#define CTRLIF_DATA      0
+#define CTRLIF_COMMAND   1
+#define CTRLIF_STATUS    1
+#define CTRLIF_SIZE_LOW  2
+#define CTRLIF_SIZE_HIGH 3
+
+#define CMDREG_HC        1 /* Host control */
+#define CMDREG_SW        2 /* Size write */
+#define CMDREG_SR        4 /* Size read */
+#define CMDREG_RS        8 /* Reset interface */
+#define CMDREG_FRIE   0x40 /* Enable FR interrupt */
+#define CMDREG_DAIE   0x80 /* Enable DA interrupt */
+#define IRQEN (CMDREG_DAIE)
+
+#define STATUSREG_RE     1 /* read error */
+#define STATUSREG_WE     2 /* write error */
+#define STATUSREG_FR  0x40 /* module free */
+#define STATUSREG_DA  0x80 /* data available */
+#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE) /* general transfer error */
+
+
+#define DVB_CA_SLOTSTATE_NONE           0
+#define DVB_CA_SLOTSTATE_UNINITIALISED  1
+#define DVB_CA_SLOTSTATE_RUNNING        2
+#define DVB_CA_SLOTSTATE_INVALID        3
+#define DVB_CA_SLOTSTATE_WAITREADY      4
+#define DVB_CA_SLOTSTATE_VALIDATE       5
+#define DVB_CA_SLOTSTATE_WAITFR         6
+#define DVB_CA_SLOTSTATE_LINKINIT       7
+
+
+/* Information on a CA slot */
+struct dvb_ca_slot {
+
+        /* current state of the CAM */
+        int slot_state;
+
+        /* Number of CAMCHANGES that have occurred since last processing */
+        atomic_t camchange_count;
+
+        /* Type of last CAMCHANGE */
+        int camchange_type;
+
+        /* base address of CAM config */
+        u32 config_base;
+
+        /* value to write into Config Control register */
+        u8 config_option;
+
+        /* if 1, the CAM supports DA IRQs */
+        u8 da_irq_supported:1;
+
+        /* size of the buffer to use when talking to the CAM */
+        int link_buf_size;
+
+        /* semaphore for syncing access to slot structure */
+        struct semaphore sem;
+
+        /* buffer for incoming packets */
+        struct dvb_ringbuffer rx_buffer;
+
+        /* timer used during various states of the slot */
+        unsigned long timeout;
+};
+
+/* Private CA-interface information */
+struct dvb_ca_private {
+
+        /* pointer back to the public data structure */
+        struct dvb_ca_en50221* pub;
+
+        /* the DVB device */
+        struct dvb_device *dvbdev;
+
+        /* Flags describing the interface (DVB_CA_FLAG_*) */
+        u32 flags;
+
+        /* number of slots supported by this CA interface */
+        unsigned int slot_count;
+
+        /* information on each slot */
+        struct dvb_ca_slot* slot_info;
+
+        /* wait queues for read() and write() operations */
+        wait_queue_head_t wait_queue;
+
+        /* PID of the monitoring thread */
+        pid_t thread_pid;
+
+        /* Wait queue used when shutting thread down */
+        wait_queue_head_t thread_queue;
+
+        /* Flag indicating when thread should exit */
+        int exit:1;
+
+        /* Flag indicating if the CA device is open */
+        int open:1;
+
+        /* Flag indicating the thread should wake up now */
+        int wakeup:1;
+
+        /* Delay the main thread should use */
+        unsigned long delay;
+
+        /* Slot to start looking for data to read from in the next user-space read operation */
+        int next_read_slot;
+};
+
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private* ca);
+static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebuf, int ecount);
+static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* ebuf, int ecount);
+
+
+/**
+ * Safely find needle in haystack.
+ *
+ * @param haystack Buffer to look in.
+ * @param hlen Number of bytes in haystack.
+ * @param needle Buffer to find.
+ * @param nlen Number of bytes in needle.
+ * @return Pointer into haystack needle was found at, or NULL if not found.
+ */
+static u8* findstr(u8* haystack, int hlen, u8* needle, int nlen)
+{
+        int i;
+
+        if (hlen < nlen) return NULL;
+
+        for(i=0; i<= hlen - nlen; i++) {
+                  if (!strncmp(haystack+i, needle, nlen)) return haystack+i;
+        }
+
+        return NULL;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 physical interface functions */
+
+
+/**
+ * Check CAM status.
+ */
+static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private* ca, int slot)
+{
+        int slot_status;
+        int status;
+        int cam_present_now;
+        int cam_changed;
+
+        /* IRQ mode */
+        if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {
+                return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);
+        }
+
+        /* poll mode */
+        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
+        slot_status = ca->pub->poll_slot_status(ca->pub, slot);
+        up(&ca->slot_info[slot].sem);
+
+        cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1: 0;
+        cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1: 0;
+        if (!cam_changed) {
+                int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);
+                cam_changed = (cam_present_now != cam_present_old);
+        }
+
+        if (cam_changed) {
+                if (!cam_present_now) {
+                        ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+                } else {
+                        ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+                }
+                atomic_set(&ca->slot_info[slot].camchange_count, 1);
+        } else {
+                if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
+                    (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
+                        // move to validate state if reset is completed
+                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+                }
+        }
+
+        return cam_changed;
+}
+
+
+/**
+ * Wait for flags to become set on the STATUS register on a CAM interface,
+ * checking for errors and timeout.
+ *
+ * @param ca CA instance.
+ * @param slot Slot on interface.
+ * @param waitfor Flags to wait for.
+ * @param timeout_ms Timeout in milliseconds.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private* ca, int slot, u8 waitfor, int timeout_hz)
+{
+        unsigned long timeout;
+        unsigned long start;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* loop until timeout elapsed */
+        start = jiffies;
+        timeout = jiffies + timeout_hz;
+        while(1) {
+                /* read the status and check for error */
+                int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+                if (res < 0) return -EIO;
+
+                /* if we got the flags, it was successful! */
+                if (res & waitfor) {
+                        dprintk("%s succeeded timeout:%lu\n", __FUNCTION__, jiffies - start);
+                        return 0;
+                }
+
+                /* check for timeout */
+                if (time_after(jiffies, timeout)) {
+                        break;
+                }
+
+                /* wait for a bit */
+                dvb_delay(1);
+        }
+
+        dprintk("%s failed timeout:%lu\n", __FUNCTION__, jiffies - start);
+
+        /* if we get here, we've timed out */
+        return -ETIMEDOUT;
+}
+
+
+/**
+ * Initialise the link layer connection to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ *
+ * @return 0 on success, nonzero on failure.
+ */
+static int dvb_ca_en50221_link_init(struct dvb_ca_private* ca, int slot)
+{
+        int ret;
+        int buf_size;
+        u8 buf[2];
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* we'll be determining these during this function */
+        ca->slot_info[slot].da_irq_supported = 0;
+
+        /* reset the link interface. Note CAM IRQs are disabled */
+        if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, CMDREG_RS)) != 0) return ret;
+        if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ/10)) != 0) return ret;
+
+        /* set the host link buffer size temporarily. it will be overwritten with the
+         * real negotiated size later. */
+        ca->slot_info[slot].link_buf_size = 2;
+
+        /* read the buffer size from the CAM */
+        if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) return ret;
+        if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ/10)) != 0) return ret;
+        if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) return -EIO;
+        if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) return ret;
+
+        /* store it, and choose the minimum of our buffer and the CAM's buffer size */
+        buf_size = (buf[0] << 8) | buf[1];
+        if (buf_size > HOST_LINK_BUF_SIZE) buf_size = HOST_LINK_BUF_SIZE;
+        ca->slot_info[slot].link_buf_size = buf_size;
+        buf[0] = buf_size >> 8;
+        buf[1] = buf_size & 0xff;
+        dprintk("Chosen link buffer size of %i\n", buf_size);
+
+        /* write the buffer size to the CAM */
+        if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) return ret;
+        if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ/10)) != 0) return ret;
+        if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) return -EIO;
+        if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) return ret;
+
+        /* success */
+        return 0;
+}
+
+/**
+ * Read a tuple from attribute memory.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ * @param address Address to read from. Updated.
+ * @param tupleType Tuple id byte. Updated.
+ * @param tupleLength Tuple length. Updated.
+ * @param tuple Dest buffer for tuple (must be 256 bytes). Updated.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_read_tuple(struct dvb_ca_private* ca, int slot,
+                                     int* address, int* tupleType, int* tupleLength, u8* tuple)
+{
+        int i;
+        int _tupleType;
+        int _tupleLength;
+        int _address = *address;
+
+        /* grab the next tuple length and type */
+        if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) return _tupleType;
+        if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address+2)) < 0) return _tupleLength;
+        _address += 4;
+
+        dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
+
+        /* read in the whole tuple */
+        for(i=0; i< _tupleLength; i++) {
+                tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i*2));
+                dprintk("  0x%02x: 0x%02x %c\n", i, tuple[i] & 0xff, ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
+        }
+        _address += (_tupleLength*2);
+
+        // success
+        *tupleType = _tupleType;
+        *tupleLength = _tupleLength;
+        *address = _address;
+        return 0;
+}
+
+
+/**
+ * Parse attribute memory of a CAM module, extracting Config register, and checking
+ * it is a DVB CAM module.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot)
+{
+        int address = 0;
+        int tupleLength;
+        int tupleType;
+        u8 tuple[257];
+        char* dvb_str;
+        int rasz;
+        int status;
+        int got_cftableentry = 0;
+        int end_chain = 0;
+        int i;
+        u16 manfid = 0;
+        u16 devid = 0;
+
+
+        // CISTPL_DEVICE_0A
+        if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status;
+        if (tupleType != 0x1D) return -EINVAL;
+
+
+
+        // CISTPL_DEVICE_0C
+        if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status;
+        if (tupleType != 0x1C) return -EINVAL;
+
+
+
+        // CISTPL_VERS_1
+        if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status;
+        if (tupleType != 0x15) return -EINVAL;
+
+
+
+        // CISTPL_MANFID
+        if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status;
+        if (tupleType != 0x20) return -EINVAL;
+        if (tupleLength != 4) return -EINVAL;
+        manfid = (tuple[1] << 8) | tuple[0];
+        devid = (tuple[3] << 8) | tuple[2];
+
+
+
+        // CISTPL_CONFIG
+        if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status;
+        if (tupleType != 0x1A) return -EINVAL;
+        if (tupleLength < 3) return -EINVAL;
+
+        /* extract the configbase */
+        rasz = tuple[0] & 3;
+        if (tupleLength < (3 + rasz + 14)) return -EINVAL;
+        ca->slot_info[slot].config_base = 0;
+        for(i=0; i< rasz+1; i++) {
+                ca->slot_info[slot].config_base |= (tuple[2+i] << (8*i));
+        }
+
+        /* check it contains the correct DVB string */
+        dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+        if (dvb_str == NULL) return -EINVAL;
+        if (tupleLength < ((dvb_str - (char*) tuple) + 12)) return -EINVAL;
+
+        /* is it a version we support? */
+        if (strncmp(dvb_str + 8, "1.00", 4)) {
+                printk("dvb_ca: Unsupported DVB CAM module version %c%c%c%c\n",
+                        dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
+                return -EINVAL;
+        }
+
+        /* process the CFTABLE_ENTRY tuples, and any after those */
+        while((!end_chain) && (address < 0x1000)) {
+                if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status;
+                switch(tupleType) {
+                case 0x1B: // CISTPL_CFTABLE_ENTRY
+                        if (tupleLength < (2+11+17)) break;
+
+                        /* if we've already parsed one, just use it */
+                        if (got_cftableentry) break;
+
+                        /* get the config option */
+                        ca->slot_info[slot].config_option = tuple[0] & 0x3f;
+
+                        /* OK, check it contains the correct strings */
+                        if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+                            (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) break;
+
+                        got_cftableentry = 1;
+                        break;
+
+                case 0x14: // CISTPL_NO_LINK
+                        break;
+
+                case 0xFF: // CISTPL_END
+                        end_chain = 1;
+                        break;
+
+                default: /* Unknown tuple type - just skip this tuple and move to the next one */
+                        dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, tupleLength);
+                        break;
+                }
+        }
+
+        if ((address > 0x1000) || (!got_cftableentry)) return -EINVAL;
+
+        dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
+                manfid, devid,
+                ca->slot_info[slot].config_base,
+                ca->slot_info[slot].config_option);
+
+        // success!
+        return 0;
+}
+
+
+/**
+ * Set CAM's configoption correctly.
+ *
+ * @param ca CA instance.
+ * @param slot Slot containing the CAM.
+ */
+static int dvb_ca_en50221_set_configoption(struct dvb_ca_private* ca, int slot)
+{
+        int configoption;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* set the config option */
+        ca->pub->write_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);
+
+        /* check it */
+        configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
+        dprintk("Set configoption 0x%x, read configoption 0x%x\n", 
+		ca->slot_info[slot].config_option, configoption & 0x3f);
+
+        /* fine! */
+        return 0;
+
+}
+
+
+/**
+ * This function talks to an EN50221 CAM control interface. It reads a buffer of
+ * data from the CAM. The data can either be stored in a supplied buffer, or
+ * automatically be added to the slot's rx_buffer.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to read from.
+ * @param ebuf If non-NULL, the data will be written to this buffer. If NULL,
+ * the data will be added into the buffering system as a normal fragment.
+ * @param ecount Size of ebuf. Ignored if ebuf is NULL.
+ *
+ * @return Number of bytes read, or < 0 on error
+ */
+static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebuf, int ecount)
+{
+        int bytes_read;
+        int status;
+        u8 buf[HOST_LINK_BUF_SIZE];
+        int i;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* acquire the slot */
+        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
+
+        /* check if we have space for a link buf in the rx_buffer */
+        if (ebuf == NULL) {
+                if (dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer) <
+                    (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
+                        status = -EAGAIN;
+                        goto exit;
+                }
+        }
+
+        /* reset the interface if there's been a tx error */
+        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;
+        if (status & STATUSREG_TXERR) {
+                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+                status = -EIO;
+                goto exit;
+        }
+        if (!(status & STATUSREG_DA)) {
+                /* no data */
+                status = 0;
+                goto exit;
+        }
+
+        /* read the amount of data */
+        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) goto exit;
+        bytes_read = status << 8;
+        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) goto exit;
+        bytes_read |= status;
+
+        /* check it will fit */
+        if (ebuf == NULL) {
+                if (bytes_read > ca->slot_info[slot].link_buf_size) {
+                        printk("dvb_ca: CAM tried to send a buffer larger than the link buffer size!\n");
+                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+                        status = -EIO;
+                        goto exit;
+                }
+                if (bytes_read < 2) {
+                        printk("dvb_ca: CAM sent a buffer that was less than 2 bytes!\n");
+                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+                        status = -EIO;
+                        goto exit;
+                }
+        } else {
+                if (bytes_read > ecount) {
+                        printk("dvb_ca: CAM tried to send a buffer larger than the ecount size!\n");
+                        status = -EIO;
+                        goto exit;
+                }
+        }
+
+        /* fill the buffer */
+        for(i=0; i < bytes_read; i++) {
+                /* read byte and check */
+                if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) goto exit;
+
+                /* OK, store it in the buffer */
+                buf[i] = status;
+        }
+
+        /* check for read error (RE should now go to 0) */
+        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;
+        if (status & STATUSREG_RE) {
+                status = -EIO;
+                goto exit;
+        }
+
+        /* OK, add it to the receive buffer, or copy into external buffer if supplied */
+        if (ebuf == NULL) {
+                dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read, 0);
+        } else {
+                memcpy(ebuf, buf, bytes_read);
+        }
+
+        /* wake up readers when a last_fragment is received */
+        if ((buf[1] & 0x80) == 0x00) {
+                wake_up_interruptible(&ca->wait_queue);
+        }
+
+        status = bytes_read;
+
+exit:
+        up(&ca->slot_info[slot].sem);
+        return status;
+}
+
+
+/**
+ * This function talks to an EN50221 CAM control interface. It writes a buffer of data
+ * to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to write to.
+ * @param ebuf The data in this buffer is treated as a complete link-level packet to
+ * be written.
+ * @param count Size of ebuf.
+ *
+ * @return Number of bytes written, or < 0 on error.
+ */
+static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* buf, int bytes_write)
+{
+        int status;
+        int i;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+
+        // sanity check
+        if (bytes_write > ca->slot_info[slot].link_buf_size) return -EINVAL;
+
+        /* acquire the slot */
+        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
+
+        /* reset the interface if there's been a tx error */
+        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite;
+        if (status & STATUSREG_TXERR) {
+                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+                status = -EIO;
+                goto exitnowrite;
+        }
+
+        /* check if interface is actually waiting for us to read from it */
+        if (status & STATUSREG_DA) {
+                status = -EAGAIN;
+                goto exitnowrite;
+        }
+
+        /* OK, set HC bit */
+        if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_HC)) != 0) goto exit;
+
+        /* check if interface is still free */
+        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;
+        if (!(status & STATUSREG_FR)) {
+                /* it wasn't free => try again later */
+                status = -EAGAIN;
+                goto exit;
+        }
+
+        /* send the amount of data */
+        if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) goto exit;
+        if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, bytes_write & 0xff)) != 0) goto exit;
+
+        /* send the buffer */
+        for(i=0; i < bytes_write; i++) {
+                if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) goto exit;
+        }
+
+        /* check for write error (WE should now be 0) */
+        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;
+        if (status & STATUSREG_WE) {
+                status = -EIO;
+                goto exit;
+        }
+        status = bytes_write;
+
+exit:
+        ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
+
+exitnowrite:
+        up(&ca->slot_info[slot].sem);
+        return status;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 higher level functions */
+
+
+/**
+ * A CAM has been removed => shut it down.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to shut down.
+ */
+static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot)
+{
+        int status;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
+        ca->pub->slot_shutdown(ca->pub, slot);
+        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+        if (ca->slot_info[slot].rx_buffer.data) vfree(ca->slot_info[slot].rx_buffer.data);
+        ca->slot_info[slot].rx_buffer.data = NULL;
+        up(&ca->slot_info[slot].sem);
+
+        /* need to wake up all processes to check if they're now
+           trying to write to a defunct CAM */
+        wake_up_interruptible(&ca->wait_queue);
+
+        dprintk("Slot %i shutdown\n", slot);
+
+        /* success */
+        return 0;
+}
+
+
+/**
+ * A CAMCHANGE IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ * @param change_type One of the DVB_CA_CAMCHANGE_* values.
+ */
+void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type)
+{
+        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;
+
+        dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
+
+        switch(change_type) {
+        case DVB_CA_EN50221_CAMCHANGE_REMOVED:
+        case DVB_CA_EN50221_CAMCHANGE_INSERTED:
+                break;
+
+        default:
+                return;
+        }
+
+        ca->slot_info[slot].camchange_type = change_type;
+        atomic_inc(&ca->slot_info[slot].camchange_count);
+        dvb_ca_en50221_thread_wakeup(ca);
+}
+
+
+/**
+ * A CAMREADY IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot)
+{
+        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;
+
+        dprintk("CAMREADY IRQ slot:%i\n", slot);
+
+        if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
+                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+                dvb_ca_en50221_thread_wakeup(ca);
+        }
+}
+
+
+/**
+ * An FR or DA IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* pubca, int slot)
+{
+        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;
+        int flags;
+
+        dprintk("FR/DA IRQ slot:%i\n", slot);
+
+        switch(ca->slot_info[slot].slot_state) {
+        case DVB_CA_SLOTSTATE_LINKINIT:
+                flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
+                if (flags & STATUSREG_DA) {
+                        dprintk("CAM supports DA IRQ\n");
+                        ca->slot_info[slot].da_irq_supported = 1;
+		}
+                break;
+
+        case DVB_CA_SLOTSTATE_RUNNING:
+                flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
+                if (flags & STATUSREG_DA) {
+                        dvb_ca_en50221_thread_wakeup(ca);
+                }
+                break;
+        }
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 thread functions */
+
+/**
+ * Wake up the DVB CA thread
+ *
+ * @param ca CA instance.
+ */
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private* ca)
+{
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        ca->wakeup = 1;
+        mb();
+        wake_up_interruptible(&ca->thread_queue);
+}
+
+/**
+ * Used by the CA thread to determine if an early wakeup is necessary
+ *
+ * @param ca CA instance.
+ */
+static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private* ca)
+{
+        if (ca->wakeup) {
+                ca->wakeup = 0;
+                return 1;
+        }
+        if (ca->exit) return 1;
+   
+        return 0;
+}
+
+
+/**
+ * Update the delay used by the thread.
+ *
+ * @param ca CA instance.
+ */
+static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private* ca)
+{
+        int delay;
+        int curdelay = 100000000;
+        int slot;
+
+        for(slot=0; slot < ca->slot_count; slot++) {
+                switch(ca->slot_info[slot].slot_state) {
+                default:
+                case DVB_CA_SLOTSTATE_NONE:
+                case DVB_CA_SLOTSTATE_INVALID:
+                        delay = HZ*60;
+                        if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
+                                delay = HZ/10;
+                        }
+                        break;
+
+                case DVB_CA_SLOTSTATE_UNINITIALISED:
+                case DVB_CA_SLOTSTATE_WAITREADY:
+                case DVB_CA_SLOTSTATE_VALIDATE:
+                case DVB_CA_SLOTSTATE_WAITFR:
+                case DVB_CA_SLOTSTATE_LINKINIT:
+                        delay = HZ/10;
+                        break;
+
+                case DVB_CA_SLOTSTATE_RUNNING:
+                        delay = HZ*60;
+                        if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
+                                delay = HZ/10;
+                        }
+                        if (ca->open) {
+                                if ((!ca->slot_info[slot].da_irq_supported) ||
+                                    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {
+                                        delay = HZ/100;
+                                }
+                        }
+                        break;
+                }
+
+                if (delay < curdelay) curdelay = delay;
+        }
+
+        ca->delay = curdelay;
+}
+
+
+
+/**
+ * Kernel thread which monitors CA slots for CAM changes, and performs data transfers.
+ */
+static int dvb_ca_en50221_thread(void* data)
+{
+        struct dvb_ca_private *ca = (struct dvb_ca_private*) data;
+        char name[15];
+        int slot;
+        int flags;
+        int pktcount;
+        void* rxbuf;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* setup kernel thread */
+        snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
+        dvb_kernel_thread_setup(name);
+
+        /* choose the correct initial delay */
+        dvb_ca_en50221_thread_update_delay(ca);
+
+        /* main loop */
+        while(!ca->exit) {
+                /* sleep for a bit */
+                if (!ca->wakeup) {
+                        flags = wait_event_interruptible_timeout(ca->thread_queue, dvb_ca_en50221_thread_should_wakeup(ca), ca->delay);
+                        if ((flags == -ERESTARTSYS) || ca->exit) {
+                                /* got signal or quitting */
+                                break;
+                        }
+                }
+                ca->wakeup = 0;
+
+                /* go through all the slots processing them */
+                for(slot=0; slot < ca->slot_count; slot++) {
+
+                        // check the cam status + deal with CAMCHANGEs
+                        while(dvb_ca_en50221_check_camstatus(ca, slot)) {
+                                /* clear down an old CI slot if necessary */
+                                if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) dvb_ca_en50221_slot_shutdown(ca, slot);
+
+                                /* if a CAM is NOW present, initialise it */
+                                if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
+                                }
+
+                                /* we've handled one CAMCHANGE */
+                                dvb_ca_en50221_thread_update_delay(ca);
+                                atomic_dec(&ca->slot_info[slot].camchange_count);
+                        }
+
+                        // CAM state machine
+                        switch(ca->slot_info[slot].slot_state) {
+                        case DVB_CA_SLOTSTATE_NONE:
+                        case DVB_CA_SLOTSTATE_INVALID:
+                                // no action needed
+                                break;
+
+                        case DVB_CA_SLOTSTATE_UNINITIALISED:
+                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
+                                ca->pub->slot_reset(ca->pub, slot);
+                                ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+                                break;
+
+                        case DVB_CA_SLOTSTATE_WAITREADY:
+                                if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+                                        printk("dvb_ca: PC card did not respond :(\n");
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+				        dvb_ca_en50221_thread_update_delay(ca);
+                                        break;
+                                }
+                                // no other action needed; will automatically change state when ready
+                                break;
+
+                        case DVB_CA_SLOTSTATE_VALIDATE:
+                                if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+                                        printk("dvb_ca: Invalid PC card inserted :(\n");
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+				        dvb_ca_en50221_thread_update_delay(ca);
+                                        break;
+                                }
+                                if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
+                                        printk("dvb_ca: Unable to initialise CAM :(\n");
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+				        dvb_ca_en50221_thread_update_delay(ca);
+                                        break;
+                                }
+
+                                dprintk("DVB CAM validated successfully\n");
+
+                                ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
+                                ca->wakeup = 1;
+                                break;
+
+                        case DVB_CA_SLOTSTATE_WAITFR:
+                                if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+                                        printk("dvb_ca: DVB CAM did not respond :(\n");
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+				        dvb_ca_en50221_thread_update_delay(ca);
+                                        break;
+                                }
+
+                                flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+                                if (flags & STATUSREG_FR) {
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+                                        ca->wakeup = 1;
+                                }
+                                break;
+
+                        case DVB_CA_SLOTSTATE_LINKINIT:
+                                if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+                                        printk("dvb_ca: DVB CAM link initialisation failed :(\n");
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+			                dvb_ca_en50221_thread_update_delay(ca);
+                                        break;
+                                }
+
+                                rxbuf = vmalloc(RX_BUFFER_SIZE);
+                                if (rxbuf == NULL) {
+                                        printk("dvb_ca: Unable to allocate CAM rx buffer :(\n");
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+				        dvb_ca_en50221_thread_update_delay(ca);
+                                        break;
+                                }
+                                dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
+
+                                ca->pub->slot_ts_enable(ca->pub, slot);
+                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
+                                dvb_ca_en50221_thread_update_delay(ca);
+                                printk("dvb_ca: DVB CAM detected and initialised successfully\n");
+                                break;
+
+                        case DVB_CA_SLOTSTATE_RUNNING:
+                                if (!ca->open) break;
+
+                                pktcount = 0;
+                                while(dvb_ca_en50221_read_data(ca, slot, NULL, 0) > 0) {
+                                        if (!ca->open) break;
+
+                                        /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
+                                        if (dvb_ca_en50221_check_camstatus(ca, slot)) {
+                                                // we dont want to sleep on the next iteration so we can handle the cam change
+                                                ca->wakeup = 1;
+                                                break;
+                                        }
+
+                                        /* check if we've hit our limit this time */
+                                        if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
+                                                // dont sleep; there is likely to be more data to read
+                                                ca->wakeup = 1;
+                                                break;
+                                        }
+                                }
+                                break;
+                        }
+                }
+        }
+
+        /* completed */
+        ca->thread_pid = 0;
+        mb();
+        wake_up_interruptible (&ca->thread_queue);
+        return 0;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 IO interface functions */
+
+/**
+ * Real ioctl implementation.
+ * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ * @param cmd IOCTL command.
+ * @param arg Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg)
+{
+        struct dvb_device* dvbdev=(struct dvb_device*) file->private_data;
+        struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv;
+        int err=0;
+        int slot;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        switch (cmd) {
+        case CA_RESET:
+                for(slot = 0; slot < ca->slot_count; slot++) {
+                        if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
+                                dvb_ca_en50221_slot_shutdown(ca, slot);
+                                if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
+                                        dvb_ca_en50221_camchange_irq(ca->pub, slot, DVB_CA_EN50221_CAMCHANGE_INSERTED);
+                        }
+                }
+                ca->next_read_slot = 0;
+                dvb_ca_en50221_thread_wakeup(ca);
+                break;
+
+        case CA_GET_CAP:
+        {
+                struct ca_caps *caps = (struct ca_caps*) parg;
+
+                caps->slot_num=ca->slot_count;
+                caps->slot_type=CA_CI_LINK;
+                caps->descr_num=0;
+                caps->descr_type=0;
+                break;
+        }
+
+
+        case CA_GET_SLOT_INFO:
+        {
+                struct ca_slot_info *info=(struct ca_slot_info *)parg;
+
+                if ((info->num > ca->slot_count) || (info->num < 0))
+                        return -EINVAL;
+
+                info->type = CA_CI_LINK;
+                info->flags = 0;
+                if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) &&
+                    (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {
+                        info->flags = CA_CI_MODULE_PRESENT;
+                }
+                if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+                        info->flags |= CA_CI_MODULE_READY;
+                }
+                break;
+        }
+
+        default:
+                err=-EINVAL;
+                break;
+        }
+
+        return err;
+}
+
+
+/**
+ * Wrapper for ioctl implementation.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ * @param cmd IOCTL command.
+ * @param arg Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+        return dvb_usercopy(inode, file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
+}
+
+
+/**
+ * Implementation of write() syscall.
+ *
+ * @param file File structure.
+ * @param buf Source buffer.
+ * @param count Size of source buffer.
+ * @param ppos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+        struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
+        struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
+        u8 slot, connection_id;
+        int status;
+        char fragbuf[HOST_LINK_BUF_SIZE];
+        int fragpos = 0;
+        int fraglen;
+        unsigned long timeout;
+        int written;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+        if (count < 2) return -EINVAL;
+
+        /* extract slot & connection id */
+        if (copy_from_user(&slot, buf, 1)) return -EFAULT;
+        if (copy_from_user(&connection_id, buf+1, 1)) return -EFAULT;
+        buf+=2;
+        count-=2;
+
+        /* check if the slot is actually running */
+        if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) return -EINVAL;
+
+        /* fragment the packets & store in the buffer */
+        while(fragpos < count) {
+                fraglen = ca->slot_info[slot].link_buf_size - 2;
+                if ((count - fragpos) < fraglen) fraglen = count - fragpos;
+
+                fragbuf[0] = connection_id;
+                fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
+                if ((status = copy_from_user(fragbuf+2, buf+fragpos, fraglen)) != 0) goto exit;
+
+		timeout = jiffies + HZ/2;
+	        written = 0;
+                while(!time_after(jiffies, timeout)) {
+                        status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen+2);
+		        if (status == (fraglen+2)) {
+			       written = 1;
+			       break;
+			}
+                        if (status != -EAGAIN) goto exit;
+
+                        dvb_delay(1);
+                }
+	        if (!written) {
+		        status = -EIO;
+		        goto exit;
+		}
+
+                fragpos += fraglen;
+        }
+        status = count + 2;
+
+exit:
+        return status;
+}
+
+
+/**
+ * Condition for waking up in dvb_ca_en50221_io_read_condition
+ */
+static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* result, int* _slot)
+{
+        int slot;
+        int slot_count = 0;
+        int idx;
+        int fraglen;
+        int connection_id = -1;
+        int found = 0;
+        u8 hdr[2];
+
+        slot = ca->next_read_slot;
+        while((slot_count < ca->slot_count) && (!found)) {
+                if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot;
+
+                if ((*result = down_interruptible(&ca->slot_info[slot].sem)) != 0) return 1;
+
+                idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+                while(idx != -1) {
+                        dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+                        if (connection_id == -1) connection_id = hdr[0];
+                        if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
+                                *_slot = slot;
+                                found = 1;
+                                break;
+                        }
+
+                        idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+                }
+
+                if (!found) up(&ca->slot_info[slot].sem);
+
+nextslot:
+                slot = (slot + 1) % ca->slot_count;
+                slot_count++;
+        }
+
+        ca->next_read_slot = slot;
+        return found;
+}
+
+
+/**
+ * Implementation of read() syscall.
+ *
+ * @param file File structure.
+ * @param buf Destination buffer.
+ * @param count Size of destination buffer.
+ * @param ppos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+        struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
+        struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
+        int status;
+        int result = 0;
+        u8 hdr[2];
+        int slot;
+        int connection_id = -1;
+        size_t idx, idx2;
+        int last_fragment = 0;
+        size_t fraglen;
+        int pktlen;
+        int dispose = 0;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+        if (count < 2) return -EINVAL;
+
+        /* wait for some data */
+        if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
+
+                /* if we're in nonblocking mode, exit immediately */
+                if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK;
+
+                /* wait for some data */
+                status = wait_event_interruptible(ca->wait_queue, dvb_ca_en50221_io_read_condition(ca, &result, &slot));
+        }
+        if ((status < 0) || (result < 0)) {
+                if (result) return result;
+                return status;
+        }
+
+        idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+        pktlen = 2;
+        do {
+                if (idx == -1) {
+                        printk("dvb_ca: BUG: read packet ended before last_fragment encountered\n");
+                        status = -EIO;
+                        goto exit;
+                }
+
+                dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+                if (connection_id == -1) connection_id = hdr[0];
+                if (hdr[0] == connection_id) {
+                        if (pktlen < count) {
+                                if ((pktlen + fraglen - 2) > count) {
+                                        fraglen = count - pktlen;
+                                } else {
+                                        fraglen -= 2;
+                                }
+
+			        if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2, buf + pktlen, fraglen, 1)) < 0) {
+                                        goto exit;
+                                }
+                                pktlen += fraglen;
+                        }
+
+                        if ((hdr[1] & 0x80) == 0) last_fragment = 1;
+                        dispose = 1;
+                }
+
+                idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+                if (dispose) dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx);
+                idx = idx2;
+                dispose = 0;
+        } while (!last_fragment);
+
+        hdr[0] = slot;
+        hdr[1] = connection_id;
+        if ((status = copy_to_user(buf, hdr, 2)) != 0) goto exit;
+        status = pktlen;
+
+exit:
+        up(&ca->slot_info[slot].sem);
+        return status;
+}
+
+
+/**
+ * Implementation of file open syscall.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
+{
+        struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
+        struct dvb_ca_private *ca = (struct dvb_ca_private*) dvbdev->priv;
+        int err;
+        int i;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        err=dvb_generic_open(inode, file);
+        if (err<0)
+                return err;
+
+        for(i=0; i< ca->slot_count; i++) {
+                if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+                        dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
+                }
+        }
+
+        ca->open = 1;
+        dvb_ca_en50221_thread_update_delay(ca);
+        dvb_ca_en50221_thread_wakeup(ca);
+
+        return 0;
+}
+
+
+/**
+ * Implementation of file close syscall.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
+{
+        struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
+        struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
+        int err;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* mark the CA device as closed */
+        ca->open = 0;
+        dvb_ca_en50221_thread_update_delay(ca);
+
+        err=dvb_generic_release(inode, file);
+        if (err<0)
+                return err;
+        return 0;
+}
+
+
+/**
+ * Implementation of poll() syscall.
+ *
+ * @param file File concerned.
+ * @param wait poll wait table.
+ *
+ * @return Standard poll mask.
+ */
+static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
+{
+        struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
+        struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv;
+        unsigned int mask=0;
+        int slot;
+        int result = 0;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+                up(&ca->slot_info[slot].sem);
+                mask |= POLLIN;
+        }
+
+        /* if there is something, return now */
+        if (mask) return mask;
+
+        /* wait for something to happen */
+        poll_wait(file, &ca->wait_queue, wait);
+
+        if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+                up(&ca->slot_info[slot].sem);
+                mask |= POLLIN;
+        }
+
+        return mask;
+}
+
+
+static struct file_operations dvb_ca_fops = {
+        owner: THIS_MODULE,
+        read: dvb_ca_en50221_io_read,
+        write: dvb_ca_en50221_io_write,
+        ioctl: dvb_ca_en50221_io_ioctl,
+        open: dvb_ca_en50221_io_open,
+        release: dvb_ca_en50221_io_release,
+        poll: dvb_ca_en50221_io_poll,
+};
+
+static struct dvb_device dvbdev_ca = {
+        priv: 0,
+        users: 1,
+        readers: 1,
+        writers: 1,
+        fops: &dvb_ca_fops,
+};
+
+
+/* ******************************************************************************** */
+/* Initialisation/shutdown functions */
+
+
+/**
+ * Initialise a new DVB CA EN50221 interface device.
+ *
+ * @param dvb_adapter DVB adapter to attach the new CA device to.
+ * @param ca The dvb_ca instance.
+ * @param flags Flags describing the CA device (DVB_CA_FLAG_*).
+ * @param slot_count Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* pubca, int flags, int slot_count)
+{
+        int ret;
+        struct dvb_ca_private* ca = NULL;
+        int i;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        if (slot_count < 1) return -EINVAL;
+
+        /* initialise the system data */
+        if ((ca = (struct dvb_ca_private*) kmalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) {
+                ret = -ENOMEM;
+                goto error;
+        }
+        memset(ca, 0, sizeof(struct dvb_ca_private));
+        ca->pub = pubca;
+        ca->flags = flags;
+        ca->slot_count = slot_count;
+        if ((ca->slot_info = kmalloc(sizeof(struct dvb_ca_slot) * slot_count, GFP_KERNEL)) == NULL) {
+                ret = -ENOMEM;
+                goto error;
+        }
+        memset(ca->slot_info, 0, sizeof(struct dvb_ca_slot) * slot_count);
+        init_waitqueue_head(&ca->wait_queue);
+        ca->thread_pid = 0;
+        init_waitqueue_head(&ca->thread_queue);
+        ca->exit = 0;
+        ca->open = 0;
+        ca->wakeup = 0;
+        ca->next_read_slot = 0;
+        pubca->private = ca;
+
+        /* register the DVB device */
+        ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
+        if (ret) goto error;
+
+        /* now initialise each slot */
+        for(i=0; i< slot_count; i++) {
+                memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
+                ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
+                atomic_set(&ca->slot_info[i].camchange_count, 0);
+                ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+                init_MUTEX(&ca->slot_info[i].sem);
+        }
+
+        if (signal_pending(current)) {
+                ret = -EINTR;
+                goto error;
+        }
+        mb();
+
+        /* create a kthread for monitoring this CA device */
+        ret = kernel_thread (dvb_ca_en50221_thread, ca, 0);
+        if (ret < 0) {
+                printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret);
+                goto error;
+        }
+        ca->thread_pid = ret;
+        return 0;
+
+error:
+        if (ca != NULL) {
+                if (ca->dvbdev != NULL) dvb_unregister_device(ca->dvbdev);
+                if (ca->slot_info != NULL) kfree(ca->slot_info);
+                kfree(ca);
+        }
+        pubca->private = NULL;
+        return ret;
+}
+
+
+
+/**
+ * Release a DVB CA EN50221 interface device.
+ *
+ * @param ca_dev The dvb_device_t instance for the CA device.
+ * @param ca The associated dvb_ca instance.
+ */
+void dvb_ca_en50221_release(struct dvb_ca_en50221* pubca)
+{
+        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;
+        int i;
+
+        dprintk ("%s\n", __FUNCTION__);
+
+        /* shutdown the thread if there was one */
+        if (ca->thread_pid) {
+                if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
+                        printk("dvb_ca_release: thread PID %d already died\n", ca->thread_pid);
+                } else {
+                        ca->exit = 1;
+                        mb();
+                        dvb_ca_en50221_thread_wakeup(ca);
+                        wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0);
+                }
+        }
+
+        for(i=0; i< ca->slot_count; i++) {
+                dvb_ca_en50221_slot_shutdown(ca, i);
+        }
+        kfree(ca->slot_info);
+        dvb_unregister_device(ca->dvbdev);
+        kfree(ca);
+        pubca->private = NULL;
+}
+
+MODULE_PARM(dvb_ca_en50221_debug,"i");
+
+MODULE_PARM_DESC(dvb_ca_en50221_debug, "enable verbose debug messages");
drivers/media/dvb/dvb-core/dvb_ca_en50221.h +128 -0

128 lines not on this page · raw message

drivers/media/dvb/dvb-core/dvb_ksyms.c +6 -0
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/dvb-core/dvb_ksyms.c linux-2.6.5-patched/drivers/media/dvb/dvb-core/dvb_ksyms.c
@@ -10,6 +10,7 @@
 #include "dvb_frontend.h"
 #include "dvb_net.h"
 #include "dvb_filter.h"
+#include "dvb_ca_en50221.h"
 
 EXPORT_SYMBOL(dvb_dmxdev_init);
 EXPORT_SYMBOL(dvb_dmxdev_release);
@@ -49,3 +50,8 @@
 EXPORT_SYMBOL(dvb_filter_pes2ts);
 EXPORT_SYMBOL(dvb_filter_get_ac3info);
 
+EXPORT_SYMBOL(dvb_ca_en50221_init);
+EXPORT_SYMBOL(dvb_ca_en50221_release);
+EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
+EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
+EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
drivers/media/dvb/dvb-core/dvb_ringbuffer.c +114 -2

144 lines not on this page · raw message

drivers/media/dvb/dvb-core/dvb_ringbuffer.h +53 -2

72 lines not on this page · raw message

drivers/media/dvb/dvb-core/Makefile +2 -1
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/dvb-core/Makefile linux-2.6.5-patched/drivers/media/dvb/dvb-core/Makefile
@@ -3,6 +3,7 @@
 #
 
 dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-		dvb_functions.o dvb_frontend.o dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
+	        dvb_ca_en50221.o dvb_functions.o dvb_frontend.o \
+		dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
#6 lore raw

PATCH 6/9 DVB: AV7110 DVB driver updates

In reply to Michael Hunold

- [DVB] av7110 update:
- speed up firmware loading
- follow internal API changes in saa7146 driver
- introduced some symbolic constants for a/v dec cmds
- change default for hw_sections to 0 to enable crc checks

drivers/media/dvb/ttpci/av7110_av.c +22 -22
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/ttpci/av7110_av.c linux-2.6.5-patched/drivers/media/dvb/ttpci/av7110_av.c
@@ -975,7 +975,7 @@
 		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
 			av7110_av_stop(av7110, RP_VIDEO);
 		else
-			vidcom(av7110, 0x000e,
+			vidcom(av7110, VIDEO_CMD_STOP,
 			       av7110->videostate.video_blank ? 0 : 1);
 		av7110->trickmode = TRICK_NONE;
 		break;
@@ -984,7 +984,7 @@
 		av7110->trickmode = TRICK_NONE;
 		if (av7110->videostate.play_state == VIDEO_FREEZED) {
 			av7110->videostate.play_state = VIDEO_PLAYING;
-			vidcom(av7110, 0x000d, 0);
+			vidcom(av7110, VIDEO_CMD_PLAY, 0);
 		}
 
 		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
@@ -993,10 +993,10 @@
 				av7110->playing &= ~RP_VIDEO;
 			}
 			av7110_av_start_play(av7110, RP_VIDEO);
-			vidcom(av7110, 0x000d, 0);
+			vidcom(av7110, VIDEO_CMD_PLAY, 0);
 		} else {
 			//av7110_av_stop(av7110, RP_VIDEO);
-			vidcom(av7110, 0x000d, 0);
+			vidcom(av7110, VIDEO_CMD_PLAY, 0);
 		}
 		av7110->videostate.play_state = VIDEO_PLAYING;
 		break;
@@ -1006,14 +1006,14 @@
 		if (av7110->playing & RP_VIDEO)
 			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
 		else
-			vidcom(av7110, 0x0102, 1);
+			vidcom(av7110, VIDEO_CMD_FREEZE, 1);
 		av7110->trickmode = TRICK_FREEZE;
 		break;
 
 	case VIDEO_CONTINUE:
 		if (av7110->playing & RP_VIDEO)
 			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
-		vidcom(av7110, 0x000d, 0);
+		vidcom(av7110, VIDEO_CMD_PLAY, 0);
 		av7110->videostate.play_state = VIDEO_PLAYING;
 		av7110->trickmode = TRICK_NONE;
 		break;
@@ -1094,7 +1094,7 @@
 			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
 				      __Scan_I, 2, AV_PES, 0);
 		else
-			vidcom(av7110, 0x16, arg);
+			vidcom(av7110, VIDEO_CMD_FFWD, arg);
 		av7110->trickmode = TRICK_FAST;
 		av7110->videostate.play_state = VIDEO_PLAYING;
 		break;
@@ -1102,11 +1102,11 @@
 	case VIDEO_SLOWMOTION:
 		if (av7110->playing&RP_VIDEO) {
 			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
-			vidcom(av7110, 0x22, arg);
+			vidcom(av7110, VIDEO_CMD_SLOW, arg);
 		} else {
-			vidcom(av7110, 0x0d, 0);
-			vidcom(av7110, 0x0e, 0);
-			vidcom(av7110, 0x22, arg);
+			vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			vidcom(av7110, VIDEO_CMD_STOP, 0);
+			vidcom(av7110, VIDEO_CMD_SLOW, arg);
 		}
 		av7110->trickmode = TRICK_SLOW;
 		av7110->videostate.play_state = VIDEO_PLAYING;
@@ -1130,10 +1130,10 @@
 			if (av7110->trickmode == TRICK_SLOW) {
 				av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
 					      __Slow, 2, 0, 0);
-				vidcom(av7110, 0x22, arg);
+				vidcom(av7110, VIDEO_CMD_SLOW, arg);
 			}
 			if (av7110->trickmode == TRICK_FREEZE)
-				vidcom(av7110, 0x000e, 1);
+				vidcom(av7110, VIDEO_CMD_STOP, 1);
 		}
 		break;
 
@@ -1167,26 +1167,26 @@
 		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
 			av7110_av_stop(av7110, RP_AUDIO);
 		else
-			audcom(av7110, 1);
+			audcom(av7110, AUDIO_CMD_MUTE);
 		av7110->audiostate.play_state = AUDIO_STOPPED;
 		break;
 
 	case AUDIO_PLAY:
 		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
 			av7110_av_start_play(av7110, RP_AUDIO);
-		audcom(av7110, 2);
+		audcom(av7110, AUDIO_CMD_UNMUTE);
 		av7110->audiostate.play_state = AUDIO_PLAYING;
 		break;
 
 	case AUDIO_PAUSE:
-		audcom(av7110, 1);
+		audcom(av7110, AUDIO_CMD_MUTE);
 		av7110->audiostate.play_state = AUDIO_PAUSED;
 		break;
 
 	case AUDIO_CONTINUE:
 		if (av7110->audiostate.play_state == AUDIO_PAUSED) {
 			av7110->audiostate.play_state = AUDIO_PLAYING;
-			audcom(av7110, 0x12);
+			audcom(av7110, AUDIO_CMD_MUTE | AUDIO_CMD_PCM16);
 		}
 		break;
 
@@ -1196,14 +1196,14 @@
 
 	case AUDIO_SET_MUTE:
 	{
-		audcom(av7110, arg ? 1 : 2);
+		audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
 		av7110->audiostate.mute_state = (int) arg;
 		break;
 	}
 
 	case AUDIO_SET_AV_SYNC:
 		av7110->audiostate.AV_sync_state = (int) arg;
-		audcom(av7110, arg ? 0x0f : 0x0e);
+		audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
 		break;
 
 	case AUDIO_SET_BYPASS_MODE:
@@ -1215,15 +1215,15 @@
 
 		switch(av7110->audiostate.channel_select) {
 		case AUDIO_STEREO:
-			audcom(av7110, 0x80);
+			audcom(av7110, AUDIO_CMD_STEREO);
 			break;
 
 		case AUDIO_MONO_LEFT:
-			audcom(av7110, 0x100);
+			audcom(av7110, AUDIO_CMD_MONO_L);
 			break;
 
 		case AUDIO_MONO_RIGHT:
-			audcom(av7110, 0x200);
+			audcom(av7110, AUDIO_CMD_MONO_R);
 			break;
 
 		default:
drivers/media/dvb/ttpci/av7110.c +28 -20

128 lines not on this page · raw message

drivers/media/dvb/ttpci/av7110_hw.c +23 -31

91 lines not on this page · raw message

drivers/media/dvb/ttpci/av7110_hw.h +27 -3
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/ttpci/av7110_hw.h linux-2.6.5-patched/drivers/media/dvb/ttpci/av7110_hw.h
@@ -200,6 +200,12 @@
 	__Continue
 };
 
+enum av7110_fw_cmd_misc {
+	AV7110_FW_VIDEO_ZOOM = 1,
+	AV7110_FW_VIDEO_COMMAND,
+	AV7110_FW_AUDIO_COMMAND
+};
+
 enum av7110_command_type {
 	COMTYPE_NOCOM,
 	COMTYPE_PIDFILTER,
@@ -218,6 +224,7 @@
 	COMTYPE_VIDEO,
 	COMTYPE_AUDIO,
 	COMTYPE_CI_LL,
+	COMTYPE_MISC = 0x80
 };
 
 #define VID_NONE_PREF		0x00	/* No aspect ration processing preferred */
@@ -226,6 +233,23 @@
 #define VID_VC_AND_PS_PREF	0x03	/* PanScan and vertical Compression if allowed */
 #define VID_CENTRE_CUT_PREF	0x05	/* PanScan with zero vector */
 
+/* MPEG video decoder commands */
+#define VIDEO_CMD_STOP		0x000e
+#define VIDEO_CMD_PLAY		0x000d
+#define VIDEO_CMD_FREEZE	0x0102
+#define VIDEO_CMD_FFWD		0x0016
+#define VIDEO_CMD_SLOW		0x0022
+
+/* MPEG audio decoder commands */
+#define AUDIO_CMD_MUTE		0x0001
+#define AUDIO_CMD_UNMUTE	0x0002
+#define AUDIO_CMD_PCM16		0x0010
+#define AUDIO_CMD_STEREO	0x0080
+#define AUDIO_CMD_MONO_L	0x0100
+#define AUDIO_CMD_MONO_R	0x0200
+#define AUDIO_CMD_SYNC_OFF	0x000e
+#define AUDIO_CMD_SYNC_ON	0x000f
+
 /* firmware data interface codes */
 #define DATA_NONE		 0x00
 #define DATA_FSECTION		 0x01
@@ -457,21 +481,21 @@
 	return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data);
 }
 
-static inline void VidMode(struct av7110 *av7110, int mode)
+static inline void av7710_set_video_mode(struct av7110 *av7110, int mode)
 {
 	av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
 }
 
 static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg)
 {
-	return av7110_fw_cmd(av7110, 0x80, 0x02, 4,
+	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4,
 			     (com>>16), (com&0xffff),
 			     (arg>>16), (arg&0xffff));
 }
 
 static int inline audcom(struct av7110 *av7110, u32 com)
 {
-	return av7110_fw_cmd(av7110, 0x80, 0x03, 4,
+	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 4,
 			     (com>>16), (com&0xffff));
 }
 
drivers/media/dvb/ttpci/av7110_v4l.c +28 -25

115 lines not on this page · raw message

#5 lore raw

PATCH 5/9 DVB: Other DVB core updates

In reply to Michael Hunold

- [DVB] remove superflous memset() which caused section data to be overwritten when a) there are two sections in one TS packet, and b) the first section was smaller than 18 bytes; thanks to Jean-Claude Repetto for tracking this down
- [DVB] starting a ts filter on a running section filter's pid did break the section filter; fixed.
- [DVB] integrate ULE Decapsulation code, thanks to gcs - Global Communication & Services GmbH. and Institute for Computer Sciences Salzburg University. Hilmar Linder <[email protected]> and Wolfram Stering <[email protected]>
- [DVB] fix the module use count bugs, thanks to Hernan A.Perez Masci for his initial work on this problem
- [DVB] if dvb_frontend_internal_ioctl() returns an error code, be sure to deliver it to the calling application, don't ignore it (fixes the bug that the frontend0 doesn't respond properly to unknown ioctls...)
- [DVB] major frontend code clean up, rewritten core tuning loop. Thanks to Andrew de Quincey.
- [DVB] follow changes in dvb-core in skystar2, dvb-bt8xx

drivers/media/dvb/b2c2/skystar2.c +3 -1
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/b2c2/skystar2.c linux-2.6.5-patched/drivers/media/dvb/b2c2/skystar2.c
@@ -2242,7 +2243,7 @@
 	if (driver_initialize(pdev) != 0)
 		return -ENODEV;
 
-	dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name);
+	dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name, THIS_MODULE);
 
 	if (dvb_adapter == NULL) {
 		printk("%s: Error registering DVB adapter\n", __FUNCTION__);
@@ -2342,6 +2343,8 @@
 	{0,},
 };
 
+MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl);
+
 static struct pci_driver skystar2_pci_driver = {
 	.name = "Technisat SkyStar2 driver",
 	.id_table = skystar2_pci_tbl,
drivers/media/dvb/bt8xx/dvb-bt8xx.c +1 -1
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/bt8xx/dvb-bt8xx.c linux-2.6.5-patched/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -286,7 +286,7 @@
 	
 	}
 
-	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name)) < 0) {
+	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
 	
 		printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
 		
drivers/media/dvb/dvb-core/dvb_demux.c +0 -3
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/dvb-core/dvb_demux.c linux-2.6.5-patched/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -192,7 +194,6 @@
 	struct dvb_demux *demux = feed->demux;
 	struct dvb_demux_filter *f = feed->filter;
 	struct dmx_section_feed *sec = &feed->feed.sec;
-	u8 *buf = sec->secbuf;
 	int section_syntax_indicator;
 
 	if (!sec->is_filtering)
@@ -215,8 +216,6 @@
 
 	sec->seclen = 0;
 
-	memset(buf, 0, DVB_DEMUX_MASK_MAX);
- 
 	return 0;
 }
 
drivers/media/dvb/dvb-core/dvbdev.c +9 -3
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/dvb-core/dvbdev.c linux-2.6.5-patched/drivers/media/dvb/dvb-core/dvbdev.c
@@ -211,6 +210,8 @@
 	dvbdev->adapter = adap;
 	dvbdev->priv = priv;
 
+	dvbdev->fops->owner = adap->module;
+
 	list_add_tail (&dvbdev->list_head, &adap->device_list);
 
 	devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
@@ -227,9 +228,12 @@
 
 void dvb_unregister_device(struct dvb_device *dvbdev)
 {
-	if (dvbdev) {
+	if (!dvbdev)
+		return;
+
 		devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
 				dnames[dvbdev->type], dvbdev->id);
+
 		list_del(&dvbdev->list_head);
 		kfree(dvbdev);
 	}
@@ -233,7 +237,6 @@
 		list_del(&dvbdev->list_head);
 		kfree(dvbdev);
 	}
-}
 
 
 static int dvbdev_get_free_adapter_num (void)
@@ -257,7 +260,7 @@
 }
 
 
-int dvb_register_adapter(struct dvb_adapter **padap, const char *name)
+int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct module *module)
 {
 	struct dvb_adapter *adap;
 	int num;
@@ -281,8 +284,10 @@
 	printk ("DVB: registering new adapter (%s).\n", name);
 	
 	devfs_mk_dir("dvb/adapter%d", num);
+
 	adap->num = num;
 	adap->name = name;
+	adap->module = module;
 
 	list_add_tail (&adap->list_head, &dvb_adapter_list);
 
drivers/media/dvb/dvb-core/dvbdev.h +3 -1
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/dvb-core/dvbdev.h linux-2.6.5-patched/drivers/media/dvb/dvb-core/dvbdev.h
@@ -48,6 +48,8 @@
 	struct list_head device_list;
 	const char *name;
 	u8 proposed_mac [6];
+
+	struct module *module;
 };
 
 
@@ -75,7 +74,7 @@
 };
 
 
-extern int dvb_register_adapter (struct dvb_adapter **padap, const char *name);
+extern int dvb_register_adapter (struct dvb_adapter **padap, const char *name, struct module *module);
 extern int dvb_unregister_adapter (struct dvb_adapter *adap);
 
 extern int dvb_register_device (struct dvb_adapter *adap,
drivers/media/dvb/dvb-core/dvb_frontend.c +310 -117

604 lines not on this page · raw message

drivers/media/dvb/dvb-core/dvb_frontend.h +12 -1
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/dvb-core/dvb_frontend.h linux-2.6.5-patched/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -56,14 +56,25 @@
 	void *data;                /*  can be used by hardware module... */
 };
 
+struct dvb_frontend_tune_settings {
+        int min_delay_ms;
+        int step_size;
+        int max_drift;
+        struct dvb_frontend_parameters parameters;
+};
+
 
 /**
  *   private frontend command ioctl's.
  *   keep them in sync with the public ones defined in linux/dvb/frontend.h
+ * 
+ *   FE_SLEEP. Ioctl used to put frontend into a low power mode.
+ *   FE_INIT. Ioctl used to initialise the frontend.
+ *   FE_GET_TUNE_SETTINGS. Get the frontend-specific tuning loop settings for the supplied set of parameters.
  */
 #define FE_SLEEP              _IO('v', 80)
 #define FE_INIT               _IO('v', 81)
-#define FE_RESET              _IO('v', 82)
+#define FE_GET_TUNE_SETTINGS  _IOWR('v', 83, struct dvb_frontend_tune_settings)
 
 
 extern int
drivers/media/dvb/dvb-core/dvb_net.c +586 -30

818 lines not on this page · raw message

include/linux/dvb/frontend.h +3 -3
diff -urawBN xx-linux-2.6.5/include/linux/dvb/frontend.h linux-2.6.5-patched/include/linux/dvb/frontend.h
@@ -59,9 +59,9 @@
 	FE_CAN_BANDWIDTH_AUTO         = 0x40000,
 	FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
 	FE_CAN_HIERARCHY_AUTO         = 0x100000,
-	FE_CAN_RECOVER                = 0x20000000,
-	FE_CAN_CLEAN_SETUP            = 0x40000000,
-	FE_CAN_MUTE_TS                = 0x80000000
+	FE_NEEDS_BENDING              = 0x20000000, // frontend requires frequency bending
+	FE_CAN_RECOVER                = 0x40000000, // frontend can recover from a cable unplug automatically
+	FE_CAN_MUTE_TS                = 0x80000000  // frontend can stop spurious TS data output
 } fe_caps_t;
 
 
include/linux/dvb/net.h +13 -1
diff -urawBN xx-linux-2.6.5/include/linux/dvb/net.h linux-2.6.5-patched/include/linux/dvb/net.h
@@ -30,6 +30,9 @@
 struct dvb_net_if {
 	__u16 pid;
 	__u16 if_num;
+	__u8 feedtype;
+#define DVB_NET_FEEDTYPE_MPE 0	/* multi protocol encapsulation */
+#define DVB_NET_FEEDTYPE_ULE 1	/* ultra lightweight encapsulation */
 };
 
 
@@ -37,5 +40,14 @@
 #define NET_REMOVE_IF              _IO('o', 53)
 #define NET_GET_IF                 _IOWR('o', 54, struct dvb_net_if)
 
-#endif /*_DVBNET_H_*/
 
+/* binary compatibility cruft: */
+struct __dvb_net_if_old {
+	__u16 pid;
+	__u16 if_num;
+};
+#define __NET_ADD_IF_OLD _IOWR('o', 52, struct __dvb_net_if_old)
+#define __NET_GET_IF_OLD _IOWR('o', 54, struct __dvb_net_if_old)
+
+
+#endif /*_DVBNET_H_*/
#8 lore raw

PATCH 8/9 DVB: Misc. DVB USB driver updates

In reply to Michael Hunold

- [DVB] ttusb-dec:
- Add a parameter to dvb_filter_pes2ts function to specify whether the packet is a payload unit start or not
- Use the hotplug firmware loader for 2.6 kernels instead of compiling the firmware into the module.
- Correct the USB id of the DEC3000-s, add basic support
- [DVB] ttusb-budget:
- Remove spurious discontinuity message when starting streaming

drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +9 -10
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c linux-2.6.5-patched/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -9,7 +9,6 @@
  *	published by the Free Software Foundation; either version 2 of
  *	the License, or (at your option) any later version.
  */
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
@@ -108,9 +107,10 @@
 
 	int insync;
 
-	u16 cc;			/* MuxCounter - will increment on EVERY MUX PACKET */
+	int cc;			/* MuxCounter - will increment on EVERY MUX PACKET */
 	/* (including stuffing. yes. really.) */
 
+
 	u8 last_result[32];
 
 	struct ttusb_channel {
@@ -575,7 +575,7 @@
 
 	cc = (muxpack[len - 4] << 8) | muxpack[len - 3];
 	cc &= 0x7FFF;
-	if (cc != ttusb->cc)
+	if ((cc != ttusb->cc) && (ttusb->cc != -1))
 		printk("%s: cc discontinuity (%d frames missing)\n",
 		       __FUNCTION__, (cc - ttusb->cc) & 0x7FFF);
 	ttusb->cc = (cc + 1) & 0x7FFF;
@@ -787,7 +787,7 @@
 			ttusb_process_frame(ttusb, data, len);
 		}
 	}
-	usb_submit_urb(urb, GFP_ATOMIC);
+	usb_submit_urb(urb, GFP_KERNEL);
 }
 
 static void ttusb_free_iso_urbs(struct ttusb *ttusb)
@@ -852,6 +852,7 @@
 		return 0;
 	}
 
+	ttusb->cc = -1;
 	ttusb->insync = 0;
 	ttusb->mux_state = 0;
 
@@ -864,6 +865,7 @@
 		urb->complete = ttusb_iso_irq;
 		urb->pipe = ttusb->isoc_in_pipe;
 		urb->transfer_flags = URB_ISO_ASAP;
+		urb->interval = 1;
 		urb->number_of_packets = FRAMES_PER_ISO_BUF;
 		urb->transfer_buffer_length =
 		    ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
@@ -1008,7 +1010,6 @@
 
 static int ttusb_setup_interfaces(struct ttusb *ttusb)
 {
-	usb_set_configuration(ttusb->dev, 1);
 	usb_set_interface(ttusb->dev, 1, 1);
 
 	ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1);
@@ -1077,6 +1078,8 @@
 
 	udev = interface_to_usbdev(intf);
 
+        if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV;
+
 	if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL)))
 		return -ENOMEM;
 
@@ -1101,8 +1104,7 @@
 
 	up(&ttusb->sem);
 
-	dvb_register_adapter(&ttusb->adapter,
-			     "Technotrend/Hauppauge Nova-USB");
+	dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
 
 	dvb_register_i2c_bus(ttusb_i2c_xfer, ttusb, ttusb->adapter, 0);
 	dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL,
@@ -1169,9 +1169,6 @@
 
 	ttusb_stop_iso_xfer(ttusb);
 
-#if 0
-	devfs_remove(TTUSB_BUDGET_NAME);
-#endif
 	ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx);
 	dvb_net_release(&ttusb->dvbnet);
 	dvb_dmxdev_release(&ttusb->dmxdev);
drivers/media/dvb/ttusb-dec/ttusb_dec.c +36 -33

209 lines not on this page · raw message

#7 lore raw

PATCH 7/9 DVB: Misc. DVB frontend driver updates

In reply to Michael Hunold

- [DVB] follow changes in dvb-core for frontend drivers (ves1x93, ves1820, nxt6000, sp887x, tda1004x, stv0299, mt312, alps_tdlb7, alps_tdmb7, at76c651, cx24110, dst, dvb_dummy_fe, grundig_29504-401, grundig_29504-491)
- [DVB] tda1004x: updated timeout to 800ms, implemented FE_SLEEP
- [DVB] cx24110: add FE_CAN_RECOVER to reduce kdvb-fe CPU load
- [DVB] grundig_29504-401: added 200ms delay after first FE_INIT, Implemented FE_GET_FRONTEND
- [DVB] alps_tdlb7, alps_tdmb7: upped tuning delays to fix tuning

drivers/media/dvb/frontends/alps_tdlb7.c +22 -49
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/alps_tdlb7.c linux-2.6.5-patched/drivers/media/dvb/frontends/alps_tdlb7.c
@@ -29,11 +29,11 @@
 */  
 
 
+#define __KERNEL_SYSCALLS__
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
-#include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/delay.h>
 
@@ -56,6 +56,8 @@
 #define SP8870_FIRMWARE_OFFSET 0x0A
 
 
+static int errno;
+
 static struct dvb_frontend_info tdlb7_info = {
 	.name			= "Alps TDLB7",
 	.type			= FE_OFDM,
@@ -74,12 +75,7 @@
 static int sp8870_writereg (struct dvb_i2c_bus *i2c, u16 reg, u16 data)
 {
         u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
-	struct i2c_msg msg = {
-		.addr = 0x71,
-		.flags = 0,
-		.buf = buf,
-		.len =  4
-	};
+	struct i2c_msg msg = { .addr = 0x71, .flags = 0, .buf = buf, .len = 4 };
 	int err;
 
         if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
@@ -96,20 +92,8 @@
 	int ret;
 	u8 b0 [] = { reg >> 8 , reg & 0xff };
 	u8 b1 [] = { 0, 0 };
-	struct i2c_msg msg [] = {
-		{
-			.addr 	= 0x71,
-			.flags	= 0,
-			.buf	= b0,
-			.len	= 2
-		},
-		{
-			.addr	= 0x71,
-			.flags	= I2C_M_RD,
-			.buf	= b1,
-			.len	= 2
-		}
-	};
+	struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
+			   { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
 
 	ret = i2c->xfer (i2c, msg, 2);
 
@@ -125,12 +109,7 @@
 static int sp5659_write (struct dvb_i2c_bus *i2c, u8 data [4])
 {
         int ret;
-        struct i2c_msg msg = {
-		.addr	= 0x60,
-		.flags	= 0,
-		.buf	= data,
-		.len	=4
-	};
+        struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = 4 };
 
         ret = i2c->xfer (i2c, &msg, 1);
 
@@ -170,13 +149,13 @@
 	loff_t filesize;
 	char *dp;
 
-	fd = sys_open(fn, 0, 0);
+	fd = open(fn, 0, 0);
 	if (fd == -1) {
                 printk("%s: unable to open '%s'.\n", __FUNCTION__, fn);
 		return -EIO;
 	}
 
-	filesize = sys_lseek(fd, 0L, 2);
+	filesize = lseek(fd, 0L, 2);
 	if (filesize <= 0 || filesize < SP8870_FIRMWARE_OFFSET + SP8870_FIRMWARE_SIZE) {
 	        printk("%s: firmware filesize to small '%s'\n", __FUNCTION__, fn);
 		sys_close(fd);
@@ -190,8 +169,8 @@
 		return -EIO;
 	}
 
-	sys_lseek(fd, SP8870_FIRMWARE_OFFSET, 0);
-	if (sys_read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) {
+	lseek(fd, SP8870_FIRMWARE_OFFSET, 0);
+	if (read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) {
 		printk("%s: failed to read '%s'.\n",__FUNCTION__, fn);
 		vfree(dp);
 		sys_close(fd);
@@ -658,9 +637,6 @@
         case FE_SET_FRONTEND:
 		return sp8870_set_frontend(i2c, (struct dvb_frontend_parameters*) arg);
 
-	case FE_RESET:
-		return -EOPNOTSUPP;
-
 	case FE_GET_FRONTEND:			 // FIXME: read known values back from Hardware...
 		return -EOPNOTSUPP;
 
@@ -675,6 +651,15 @@
 		}
 		break;
 
+	case FE_GET_TUNE_SETTINGS:
+	{
+	        struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
+	        fesettings->min_delay_ms = 150;
+	        fesettings->step_size = 166667;
+	        fesettings->max_drift = 166667*2;
+	        return 0;
+	}	    
+	    
 	default:
 		return -EOPNOTSUPP;
         };
@@ -687,21 +672,8 @@
 {
         u8 b0 [] = { 0x02 , 0x00 };
         u8 b1 [] = { 0, 0 };
-        struct i2c_msg msg [] =
-			{
-				{
-					.addr = 0x71,
-					.flags = 0,
-					.buf = b0,
-					.len = 2
-				},
-				{
-					.addr = 0x71,
-					.flags = I2C_M_RD,
-					.buf = b1,
-					.len = 2
-				}
-			};
+        struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
+                                  { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
 
 	dprintk ("%s\n", __FUNCTION__);
 
drivers/media/dvb/frontends/alps_tdmb7.c +9 -3
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/alps_tdmb7.c linux-2.6.5-patched/drivers/media/dvb/frontends/alps_tdmb7.c
@@ -50,7 +50,7 @@
 	.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 	      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
 	      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | 
-	      FE_CAN_CLEAN_SETUP | FE_CAN_RECOVER
+              FE_CAN_RECOVER
 };
 
 
@@ -390,8 +390,14 @@
         case FE_INIT:
 		return cx22700_init (i2c);
 
-        case FE_RESET:
-                break;
+	case FE_GET_TUNE_SETTINGS:
+	{
+	        struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
+	        fesettings->min_delay_ms = 150;
+	        fesettings->step_size = 166667;
+	        fesettings->max_drift = 166667*2;
+	        return 0;
+	}	    
 
 	default:
 		return -EOPNOTSUPP;
drivers/media/dvb/frontends/at76c651.c +10 -5
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/at76c651.c linux-2.6.5-patched/drivers/media/dvb/frontends/at76c651.c
@@ -71,9 +71,7 @@
 	    FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
 	    FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
 	    FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 |
-	    FE_CAN_QAM_256 /* | FE_CAN_QAM_512 | FE_CAN_QAM_1024 */ |
-	    FE_CAN_RECOVER | FE_CAN_CLEAN_SETUP | FE_CAN_MUTE_TS
-
+	    FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER
 };
 
 #if ! defined(__powerpc__)
@@ -361,6 +358,7 @@
 	at76c651_set_symbolrate(i2c, p->u.qam.symbol_rate);
 	at76c651_set_inversion(i2c, p->inversion);
 	at76c651_set_auto_config(i2c);
+        at76c651_reset(i2c);
 
 	return 0;
 
@@ -462,8 +459,14 @@
 	case FE_INIT:
 		return at76c651_set_defaults(fe->i2c);
 
-	case FE_RESET:
-		return at76c651_reset(fe->i2c);
+	case FE_GET_TUNE_SETTINGS:
+	{
+	        struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
+	        fesettings->min_delay_ms = 50;
+	        fesettings->step_size = 0;
+	        fesettings->max_drift = 0;
+	        return 0;
+	}	    
 
 	default:
 		return -ENOIOCTLCMD;
drivers/media/dvb/frontends/cx24110.c +1 -7
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/cx24110.c linux-2.6.5-patched/drivers/media/dvb/frontends/cx24110.c
@@ -59,8 +59,7 @@
 	.caps = FE_CAN_INVERSION_AUTO |
 		FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK |
-		FE_CAN_CLEAN_SETUP
+		FE_CAN_QPSK | FE_CAN_RECOVER
 };
 /* fixme: are these values correct? especially ..._tolerance and caps */
 
@@ -621,11 +620,6 @@
         case FE_INIT:
 		return cx24110_init (i2c);
 
-	case FE_RESET:
-/* no idea what to do for this call */
-/* fixme (medium): fill me in */
-		break;
-
 	case FE_SET_TONE:
 		return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&~0x10)|((((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?0x10:0));
 	case FE_SET_VOLTAGE:
drivers/media/dvb/frontends/dst.c +3 -7
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/dst.c linux-2.6.5-patched/drivers/media/dvb/frontends/dst.c
@@ -963,7 +963,6 @@
 	{FE_GET_FRONTEND,            "FE_GET_FRONTEND:" },
 	{FE_SLEEP,                   "FE_SLEEP:" },
 	{FE_INIT,                    "FE_INIT:" },
-	{FE_RESET,                   "FE_RESET:" },
 	{FE_SET_TONE,                "FE_SET_TONE:" },
 	{FE_SET_VOLTAGE,             "FE_SET_VOLTAGE:" },
 	};
@@ -1091,9 +1090,6 @@
 		dst_init(dst);
 		break;
 
-	case FE_RESET:
-		break;
-
 	case FE_DISEQC_SEND_MASTER_CMD:
 	{
 		struct dvb_diseqc_master_cmd *cmd = (struct dvb_diseqc_master_cmd *)arg;
@@ -1149,8 +1145,8 @@
 	}
 
 	dst_init (dst);
-	dprintk("%s: register dst %p bt %p i2c %p\n", __FUNCTION__, 
-		dst, dst->bt, dst->i2c);
+	dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, 
+			(u32)dst, (u32)(dst->bt), (u32)(dst->i2c));
 
 	info = &dst_info_sat;
 	if (dst->dst_type == DST_TYPE_IS_TERR)
@@ -1166,7 +1162,7 @@
 static void dst_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dvb_unregister_frontend (dst_ioctl, i2c);
-	dprintk("%s: unregister dst %p\n", __FUNCTION__, data);
+	dprintk("%s: unregister dst %8.8x\n", __FUNCTION__, (u32)(data));
 	if (data)
 		kfree(data);
 }
drivers/media/dvb/frontends/dvb_dummy_fe.c +1 -5
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/dvb_dummy_fe.c linux-2.6.5-patched/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -62,8 +62,7 @@
 #endif
 	.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
 		FE_CAN_QAM_128 | FE_CAN_QAM_256 | 
-		FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO |
-		FE_CAN_CLEAN_SETUP
+		FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO
 };
 
 static struct dvb_frontend_info dvb_t_dummyfe_info = {
@@ -157,9 +156,6 @@
         case FE_INIT:
 		return 0;
 
-	case FE_RESET:
-		return 0;
-
 	case FE_SET_TONE:
 		return -EOPNOTSUPP;
 
drivers/media/dvb/frontends/grundig_29504-401.c +167 -7

241 lines not on this page · raw message

drivers/media/dvb/frontends/grundig_29504-491.c +1 -7
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/grundig_29504-491.c linux-2.6.5-patched/drivers/media/dvb/frontends/grundig_29504-491.c
@@ -52,8 +52,7 @@
 		FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 		FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
 		FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK |
-		FE_CAN_MUTE_TS | FE_CAN_CLEAN_SETUP
+		FE_CAN_QPSK | FE_CAN_MUTE_TS
 };
 
 
@@ -398,11 +397,6 @@
 		tda8083_writereg (i2c, 0x00, 0x04);
 		break;
 
-	case FE_RESET:
-		tda8083_writereg (i2c, 0x00, 0x3c);
-		tda8083_writereg (i2c, 0x00, 0x04);
-		break;
-
 	case FE_DISEQC_SEND_MASTER_CMD:
 		return tda8083_send_diseqc_msg (i2c, arg);
 
drivers/media/dvb/frontends/mt312.c +12 -4
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/mt312.c linux-2.6.5-patched/drivers/media/dvb/frontends/mt312.c
@@ -66,8 +66,8 @@
 	.caps =
 	    FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
 	    FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-	    FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_RECOVER |
-	    FE_CAN_CLEAN_SETUP | FE_CAN_MUTE_TS
+	    FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS | 
+            FE_CAN_RECOVER
 };
 
 static int mt312_read(struct dvb_i2c_bus *i2c,
@@ -570,6 +570,8 @@
 	if ((ret = mt312_write(i2c, SYM_RATE_H, buf, sizeof(buf))) < 0)
 		return ret;
 
+        mt312_reset(i2c, 0);
+
 	return 0;
 }
 
@@ -756,8 +758,14 @@
 		else
 			return mt312_init(i2c, (long) fe->data, (u8) 60);
 
-	case FE_RESET:
-		return mt312_reset(i2c, 0);
+	case FE_GET_TUNE_SETTINGS:
+	{
+	        struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
+	        fesettings->min_delay_ms = 50;
+	        fesettings->step_size = 0;
+	        fesettings->max_drift = 0;
+	        return 0;
+	}	    
 
 	default:
 		return -ENOIOCTLCMD;
drivers/media/dvb/frontends/nxt6000.c +6 -4
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/nxt6000.c linux-2.6.5-patched/drivers/media/dvb/frontends/nxt6000.c
@@ -55,7 +52,12 @@
 	.symbol_rate_max = 9360000,	/* FIXME */
 	.symbol_rate_tolerance = 4000,
 	.notifier_delay = 0,
-	.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+	.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 
+                FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | 
+                FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | 
+                FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 
+                FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | 
+                FE_CAN_HIERARCHY_AUTO,
 };
 
 struct nxt6000_config {
@@ -762,9 +662,6 @@
 			nxt6000_setup(fe);
 		break;
 
-	case FE_RESET:
-			break;
-		
 		case FE_SET_FRONTEND:
 		{
 			struct nxt6000_config *nxt = FE2NXT(fe);
drivers/media/dvb/frontends/sp887x.c +20 -18
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/sp887x.c linux-2.6.5-patched/drivers/media/dvb/frontends/sp887x.c
@@ -12,13 +12,13 @@
    next 0x4000 loaded. This may change in future versions.
  */
 
+#define __KERNEL_SYSCALLS__
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/syscalls.h>
 #include <linux/fs.h>
 #include <linux/unistd.h>
 #include <linux/fcntl.h>
@@ -64,19 +64,17 @@
 	.frequency_stepsize = 166666,
 	.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_RECOVER
+		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                FE_CAN_RECOVER
 };
 
+static int errno;
+
 static
 int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len)
 {
 	struct dvb_i2c_bus *i2c = fe->i2c;
-	struct i2c_msg msg = {
-		.addr	= addr,
-		.flags	= 0,
-		.buf	= buf,
-		.len	= len
-	};
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
 	int err;
 
 	LOG("i2c_writebytes", msg.addr, msg.buf, msg.len);
@@ -213,13 +211,13 @@
 
 	// Load the firmware
 	set_fs(get_ds());
-	fd = sys_open(sp887x_firmware, 0, 0);
+	fd = open(sp887x_firmware, 0, 0);
 	if (fd < 0) {
 		printk(KERN_WARNING "%s: Unable to open firmware %s\n", __FUNCTION__,
 		       sp887x_firmware);
 		return -EIO;
 	}
-	filesize = sys_lseek(fd, 0L, 2);
+	filesize = lseek(fd, 0L, 2);
 	if (filesize <= 0) {
 		printk(KERN_WARNING "%s: Firmware %s is empty\n", __FUNCTION__,
 		       sp887x_firmware);
@@ -241,8 +239,8 @@
 	// read it!
 	// read the first 16384 bytes from the file
 	// ignore the first 10 bytes
-	sys_lseek(fd, 10, 0);
-	if (sys_read(fd, firmware, fw_size) != fw_size) {
+	lseek(fd, 10, 0);
+	if (read(fd, firmware, fw_size) != fw_size) {
 		printk(KERN_WARNING "%s: Failed to read firmware\n", __FUNCTION__);
 		vfree(firmware);
 		sys_close(fd);
@@ -635,6 +633,15 @@
 		sp887x_writereg(fe, 0xc18, 0x00d);
 		break;
 
+	case FE_GET_TUNE_SETTINGS:
+	{
+	        struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
+	        fesettings->min_delay_ms = 50;
+	        fesettings->step_size = 0;
+	        fesettings->max_drift = 0;
+	        return 0;
+	}	    
+
 	default:
 		return -EOPNOTSUPP;
         };
@@ -647,12 +654,7 @@
 static
 int sp887x_attach (struct dvb_i2c_bus *i2c, void **data)
 {
-	struct i2c_msg msg = {
-		.addr	= 0x70,
-		.flags	= 0,
-		.buf	= NULL,
-		.len	= 0
-	};
+	struct i2c_msg msg = {.addr = 0x70, .flags = 0, .buf = NULL, .len = 0 };
 
 	dprintk ("%s\n", __FUNCTION__);
 
drivers/media/dvb/frontends/stv0299.c +207 -117

567 lines not on this page · raw message

drivers/media/dvb/frontends/tda1004x.c +54 -10

177 lines not on this page · raw message

drivers/media/dvb/frontends/ves1820.c +1 -2
diff -urawBN xx-linux-2.6.5/drivers/media/dvb/frontends/ves1820.c linux-2.6.5-patched/drivers/media/dvb/frontends/ves1820.c
@@ -111,8 +111,7 @@
 #endif
 	.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
 		FE_CAN_QAM_128 | FE_CAN_QAM_256 | 
-		FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO |
-		FE_CAN_CLEAN_SETUP | FE_CAN_RECOVER
+		FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO,
 };
 
 
drivers/media/dvb/frontends/ves1x93.c +56 -12

156 lines not on this page · raw message

#9 lore raw

PATCH 9/9 DVB: Follow saa7146 changes in affected V4L drivers

In reply to Michael Hunold

- [V4L] follow changes in saa7146 driver: mxb, dpc7146, hexium_orion, hexium_gemini

drivers/media/video/dpc7146.c +7 -7
diff -ura linux-2.6.5.q/drivers/media/video/dpc7146.c linux-2.6.5.p/drivers/media/video/dpc7146.c
@@ -106,7 +106,7 @@
 	   video port pins should be enabled here ?! */
 	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 
-	saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+	saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, I2C_ADAP_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
 	if(i2c_add_adapter(&dpc->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
 		kfree(dpc);
@@ -312,18 +312,18 @@
 static struct saa7146_standard standard[] = {
 	{
 		.name	= "PAL", 	.id	= V4L2_STD_PAL,
-		.v_offset	= 0x17,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 0x14,	.h_pixels 	= 680,	.h_calc		= 680+1,
+		.v_offset	= 0x17,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 680,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}, {
 		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
-		.v_offset	= 0x16,	.v_field 	= 240,	.v_calc		= 480,
-		.h_offset	= 0x06,	.h_pixels 	= 708,	.h_calc		= 708+1,
+		.v_offset	= 0x16,	.v_field 	= 240,
+		.h_offset	= 0x06,	.h_pixels 	= 708,
 		.v_max_out	= 480,	.h_max_out	= 640,
 	}, {
 		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
-		.v_offset	= 0x14,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 0x14,	.h_pixels 	= 720,	.h_calc		= 720+1,
+		.v_offset	= 0x14,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 720,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}
 };
drivers/media/video/hexium_gemini.c +7 -7
diff -ura linux-2.6.5.q/drivers/media/video/hexium_gemini.c linux-2.6.5.p/drivers/media/video/hexium_gemini.c
@@ -159,18 +159,18 @@
 static struct saa7146_standard hexium_standards[] = {
 	{
 		.name	= "PAL", 	.id	= V4L2_STD_PAL,
-		.v_offset	= 28,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 1,	.h_pixels 	= 680,	.h_calc		= 680+1,
+		.v_offset	= 28,	.v_field 	= 288,
+		.h_offset	= 1,	.h_pixels 	= 680,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}, {
 		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
-		.v_offset	= 28,	.v_field 	= 240,	.v_calc		= 480,
-		.h_offset	= 1,	.h_pixels 	= 640,	.h_calc		= 641+1,
+		.v_offset	= 28,	.v_field 	= 240,
+		.h_offset	= 1,	.h_pixels 	= 640,
 		.v_max_out	= 480,	.h_max_out	= 640,
 	}, {
 		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
-		.v_offset	= 28,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 1,	.h_pixels 	= 720,	.h_calc		= 720+1,
+		.v_offset	= 28,	.v_field 	= 288,
+		.h_offset	= 1,	.h_pixels 	= 720,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}
 };		
@@ -250,7 +250,7 @@
 	/* enable i2c-port pins */
 	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 
-	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, I2C_ADAP_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
 		kfree(hexium);
drivers/media/video/hexium_orion.c +7 -7
diff -ura linux-2.6.5.q/drivers/media/video/hexium_orion.c linux-2.6.5.p/drivers/media/video/hexium_orion.c
@@ -192,18 +192,18 @@
 static struct saa7146_standard hexium_standards[] = {
 	{
 		.name	= "PAL", 	.id	= V4L2_STD_PAL,
-		.v_offset	= 16,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 1,	.h_pixels 	= 680,	.h_calc		= 680+1,
+		.v_offset	= 16,	.v_field 	= 288,
+		.h_offset	= 1,	.h_pixels 	= 680,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}, {
 		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
-		.v_offset	= 16,	.v_field 	= 240,	.v_calc		= 480,
-		.h_offset	= 1,	.h_pixels 	= 640,	.h_calc		= 641+1,
+		.v_offset	= 16,	.v_field 	= 240,
+		.h_offset	= 1,	.h_pixels 	= 640,
 		.v_max_out	= 480,	.h_max_out	= 640,
 	}, {
 		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
-		.v_offset	= 16,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 1,	.h_pixels 	= 720,	.h_calc		= 720+1,
+		.v_offset	= 16,	.v_field 	= 288,
+		.h_offset	= 1,	.h_pixels 	= 720,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}
 };		
@@ -237,7 +237,7 @@
 	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
 	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
-	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, I2C_ADAP_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
 		kfree(hexium);
drivers/media/video/mxb.c +9 -9
diff -ura linux-2.6.5.q/drivers/media/video/mxb.c linux-2.6.5.p/drivers/media/video/mxb.c
@@ -183,7 +183,7 @@
 	}
 	memset(mxb, 0x0, sizeof(struct mxb));	
 
-	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
+	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, I2C_ADAP_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
 	if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
 		kfree(mxb);
@@ -942,23 +942,23 @@
 static struct saa7146_standard standard[] = {
 	{
 		.name	= "PAL-BG", 	.id	= V4L2_STD_PAL_BG,
-		.v_offset	= 0x17,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 0x14,	.h_pixels 	= 680,	.h_calc		= 680+1,
+		.v_offset	= 0x17,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 680,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}, {
 		.name	= "PAL-I", 	.id	= V4L2_STD_PAL_I,
-		.v_offset	= 0x17,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 0x14,	.h_pixels 	= 680,	.h_calc		= 680+1,
+		.v_offset	= 0x17,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 680,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}, {
 		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
-		.v_offset	= 0x16,	.v_field 	= 240,	.v_calc		= 480,
-		.h_offset	= 0x06,	.h_pixels 	= 708,	.h_calc		= 708+1,
+		.v_offset	= 0x16,	.v_field 	= 240,
+		.h_offset	= 0x06,	.h_pixels 	= 708,
 		.v_max_out	= 480,	.h_max_out	= 640,
 	}, {
 		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
-		.v_offset	= 0x14,	.v_field 	= 288,	.v_calc		= 576,
-		.h_offset	= 0x14,	.h_pixels 	= 720,	.h_calc		= 720+1,
+		.v_offset	= 0x14,	.v_field 	= 288,
+		.h_offset	= 0x14,	.h_pixels 	= 720,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}
 };
#10 lore raw

Re: [PATCH 2/9] DVB: Documentation and Kconfig updazes

In reply to Michael Hunold
Quoted 7 lines · Michael Hunold

diff -urawBN xx-linux-2.6.5/drivers/media/dvb/Kconfig linux-2.6.5-patched/drivers/media/dvb/Kconfig

drivers/media/dvb/Kconfig +0 -0
@@ -18,12 +18,11 @@
 	  Please report problems regarding this driver to the LinuxDVB 
 	  mailing list.
 

drivers/media/dvb/Kconfig line 27

Quoted 10 lines
drivers/media/dvb/Kconfig +2 -3
-	  You might want add the following lines to your /etc/modprobe.conf:
+	  You might want add the following lines to your /etc/modules.conf:
 
 	  	alias char-major-250 dvb
 	  	alias dvb dvb-ttpci
-	  	install dvb-ttpci /sbin/modprobe --first-time -i dvb-ttpci && \
-			/sbin/modprobe -a alps_bsru6 alps_bsrv2 \
+	  	below dvb-ttpci alps_bsru6 alps_bsrv2 \
 	  			grundig_29504-401 grundig_29504-491 \
 	  			ves1820

This looks wrong for a 2.6 kernel.

Signature · 2 lines
Måns Rullgård
[email protected]