public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [linux-dvb] [PATCH 2/5] SPI interface driver for Siano's SMS chip-set based devices.
@ 2008-11-19  9:03 Uri Shkolnik
  2008-11-19 10:24 ` Christophe Thommeret
  0 siblings, 1 reply; 10+ messages in thread
From: Uri Shkolnik @ 2008-11-19  9:03 UTC (permalink / raw)
  To: Linux-dvb

[-- Attachment #1: Type: text/plain, Size: 202 bytes --]

This patch provides SPI interface driver for SMS chip-set based devices.
The patch includes common SMS SPI code, and adapter driver for PXA310


Signed-off-by: Uri Shkolnik <uris@siano-ms.com>



      

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: smsspi_patch.diff --]
[-- Type: text/x-diff; name="smsspi_patch.diff", Size: 78514 bytes --]

This patch provides SPI interface driver for SMS chip-set based devices.
The patch includes common SMS SPI code, and adapter driver for PXA310


Signed-off-by: Uri Shkolnik <uris@siano-ms.com>

diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsdbg_prn.h v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsdbg_prn.h
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsdbg_prn.h	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsdbg_prn.h	2008-11-18 18:14:34.000000000 +0200
@@ -0,0 +1,56 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef _SMS_DBG_H_
+#define _SMS_DBG_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/************************************************************************/
+/* Debug Zones definitions.                                             */
+/************************************************************************/
+#undef PERROR
+#  define PERROR(fmt, args...) \
+	printk(KERN_ERR "spibus error: line %d- %s(): " fmt, __LINE__,\
+	  __func__, ## args)
+#undef PWARNING
+#  define PWARNING(fmt, args...) \
+	printk(KERN_WARNING "spibus warning: line %d- %s(): " fmt, __LINE__,  \
+	__func__, ## args)
+
+/* the debug macro - conditional compilation from the makefile */
+#undef PDEBUG			/* undef it, just in case */
+#ifdef SPIBUS_DEBUG
+#  define PDEBUG(fmt, args...) \
+	printk(KERN_DEBUG "spibus: line %d- %s(): " fmt, __LINE__, \
+	 __func__, ## args)
+#else
+#  define PDEBUG(fmt, args...)	/* not debugging: nothing */
+#endif
+
+/* The following defines are used for printing and
+are mandatory for compilation. */
+#define TXT(str) str
+#define PRN_DBG(str) PDEBUG str
+#define PRN_ERR(str) PERROR str
+
+#endif /*_SMS_DBG_H_*/
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.c v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.c
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.c	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.c	2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,326 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#include "smsspicommon.h"
+#include "smsdbg_prn.h"
+
+static int smsspi_common_find_msg(struct spi_dev *dev, rx_buffer_st * buf,
+				  int offset, int len, int *unused_bytes)
+{
+	int i, missing_bytes;
+	int recieved_bytes, padded_msg_len;
+	int align_fix;
+	char *ptr = (char *)buf->ptr + offset;
+
+	PRN_DBG((TXT("entering with %d bytes.\n"), len));
+	missing_bytes = 0;
+	for (i = 0; i < len; i++, ptr++) {
+		switch (dev->rxState) {
+		case RxsWait_a5:
+			dev->rxState =
+			    ((*ptr & 0xff) == 0xa5) ? RxsWait_5a : RxsWait_a5;
+			dev->rxPacket.msg_offset =
+			    (unsigned long)ptr - (unsigned long)buf->ptr + 4;
+			break;
+		case RxsWait_5a:
+			dev->rxState =
+			    ((*ptr & 0xff) == 0x5a) ? RxsWait_e7 : RxsWait_a5;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsWait_e7:
+			dev->rxState =
+			    ((*ptr & 0xff) == 0xe7) ? RxsWait_7e : RxsWait_a5;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsWait_7e:
+			dev->rxState =
+			    ((*ptr & 0xff) == 0x7e) ? RxsTypeH : RxsWait_a5;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsTypeH:
+			dev->rxPacket.msg_buf = buf;
+			dev->rxPacket.msg_offset =
+			    (unsigned long)ptr - (unsigned long)buf->ptr;
+			dev->rxState = RxsTypeL;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsTypeL:
+			dev->rxState = RxsGetSrcId;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsGetSrcId:
+			dev->rxState = RxsGetDstId;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsGetDstId:
+			dev->rxState = RxsGetLenL;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsGetLenL:
+			dev->rxState = RxsGetLenH;
+			dev->rxPacket.msg_len = (*ptr & 0xff);
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsGetLenH:
+			dev->rxState = RxsFlagsL;
+			dev->rxPacket.msg_len += (*ptr & 0xff) << 8;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsFlagsL:
+			dev->rxState = RxsFlagsH;
+			dev->rxPacket.msg_flags = (*ptr & 0xff);
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsFlagsH:
+			dev->rxState = RxsData;
+			dev->rxPacket.msg_flags += (*ptr & 0xff) << 8;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsData:
+			recieved_bytes =
+			    len + offset - dev->rxPacket.msg_offset;
+			padded_msg_len =
+			    ((dev->rxPacket.msg_len + 4 + SPI_PACKET_SIZE -
+			      1) >> SPI_PACKET_SIZE_BITS) <<
+			    SPI_PACKET_SIZE_BITS;
+			if (recieved_bytes < padded_msg_len) {
+				*unused_bytes = 0;
+				return padded_msg_len - recieved_bytes;
+			}
+			dev->rxState = RxsWait_a5;
+			if (dev->cb.msg_found_cb) {
+				align_fix = 0;
+				if (dev->rxPacket.
+				    msg_flags & MSG_HDR_FLAG_SPLIT_MSG_HDR) {
+					align_fix =
+					    (dev->rxPacket.
+					     msg_flags >> 8) & 0x3;
+					if (align_fix) {
+					/* The FW alligned the message data
+					therefore - alligment bytes should be
+					thrown away. Throw the aligment bytes
+					by moving the header ahead over the
+					alligment bytes. */
+						ptr =
+						    (char *)dev->rxPacket.
+						    msg_buf->ptr +
+						    dev->rxPacket.msg_offset;
+
+						/* Restore header to original
+						state before alignment changes
+						*/
+						u16 length =
+						    (ptr[5] << 8) | ptr[4];
+						length -= align_fix;
+						ptr[5] = length >> 8;
+						ptr[4] = length & 0xff;
+						/* Zero alignment flags */
+						ptr[7] &= 0xfc;
+
+						for (i = MSG_HDR_LEN - 1;
+						     i >= 0; i--) {
+							ptr[i + align_fix] =
+							    ptr[i];
+						}
+						dev->rxPacket.msg_offset +=
+						    align_fix;
+					}
+				}
+
+				PRN_DBG((TXT
+				("Msg found and sent to callback func.\n")));
+				dev->cb.msg_found_cb(dev->context,
+						     dev->rxPacket.msg_buf,
+						     dev->rxPacket.msg_offset,
+						     dev->rxPacket.msg_len -
+						     align_fix);
+				*unused_bytes =
+				    len + offset - dev->rxPacket.msg_offset -
+				    dev->rxPacket.msg_len;
+				if (*unused_bytes == 0)
+					*unused_bytes = -1;
+				return 0;
+			} else {
+				PRN_DBG((TXT
+		 ("Msg found but no callback. therefore - thrown away.\n")));
+			}
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		}
+	}
+
+	if (dev->rxState == RxsWait_a5) {
+		*unused_bytes = 0;
+		return 0;
+	} else {
+		/* Workaround to corner case: if the last byte of the buffer
+		is "a5" (first byte of the preamble), the host thinks it should
+		send another 256 bytes.  In case the a5 is the firmware
+		underflow byte, this will cause an infinite loop, so we check
+		for this case explicity. */
+		if ((dev->rxState == RxsWait_5a) && (*(ptr - 2) == 0xa5)) {
+			dev->rxState = RxsWait_a5;
+			*unused_bytes = 0;
+			return 0;
+		}
+
+		if (dev->rxPacket.msg_offset >= (SPI_PACKET_SIZE + 4))
+			/* adding 4 for the preamble. */
+		{		/*The packet will be copied to a new buffer
+				   and rescaned by the state machine */
+			*unused_bytes = dev->rxState - RxsWait_a5;
+			dev->rxState = RxsWait_a5;
+			dev->cb.free_rx_buf(dev->context, buf);
+			return 0;
+		} else {
+			/* report missing bytes and continue
+			   with message scan. */
+			*unused_bytes = 0;
+			return SPI_PACKET_SIZE;
+		}
+	}
+}
+
+void smsspi_common_transfer_msg(struct spi_dev *dev, struct spi_msg *txmsg,
+				int padding_allowed)
+{
+	int len, bytes_to_transfer;
+	unsigned long tx_phy_addr;
+	int missing_bytes, tx_bytes;
+	int offset, unused_bytes;
+	int align_block;
+	char *txbuf;
+	rx_buffer_st * buf, *tmp_buf;
+
+	len = 0;
+	if (!dev->cb.transfer_data_cb) {
+		PRN_ERR((TXT
+		("function called while module is not initialized.\n")));
+		return;
+	}
+	if (txmsg == 0) {
+		bytes_to_transfer = SPI_PACKET_SIZE;
+		txbuf = 0;
+		tx_phy_addr = 0;
+		tx_bytes = 0;
+	} else {
+		tx_bytes = txmsg->len;
+		if (padding_allowed)
+			bytes_to_transfer =
+			    (((tx_bytes + SPI_PACKET_SIZE -
+			       1) >> SPI_PACKET_SIZE_BITS) <<
+			     SPI_PACKET_SIZE_BITS);
+		else
+			bytes_to_transfer = (((tx_bytes + 3) >> 2) << 2);
+		txbuf = txmsg->buf;
+		tx_phy_addr = txmsg->buf_phy_addr;
+	}
+	offset = 0;
+	unused_bytes = 0;
+	buf =
+	    dev->cb.allocate_rx_buf(dev->context,
+				    RX_PACKET_SIZE + SPI_PACKET_SIZE);
+	if (!buf) {
+		PRN_ERR((TXT("Failed to allocate RX buffer.\n")));
+		return;
+	}
+	while (bytes_to_transfer || unused_bytes) {
+		if ((unused_bytes <= 0) && (bytes_to_transfer > 0)) {
+			len = min(bytes_to_transfer, RX_PACKET_SIZE);
+			PRN_DBG((TXT("transfering block of %d bytes\n"), len));
+			dev->cb.transfer_data_cb(dev->phy_context, txbuf,
+						 tx_phy_addr,
+						 (char *)buf->ptr + offset,
+						 buf->phy_addr + offset, len);
+		}
+		missing_bytes =
+		    smsspi_common_find_msg(dev, buf, offset, len,
+					   &unused_bytes);
+		if (bytes_to_transfer)
+			bytes_to_transfer -= len;
+
+		if (tx_bytes)
+			tx_bytes -= len;
+
+		if (missing_bytes)
+			offset += len;
+
+		if (unused_bytes) {
+			tmp_buf =
+			    dev->cb.allocate_rx_buf(dev->context,
+						    RX_PACKET_SIZE);
+			if (!tmp_buf) {
+				PRN_ERR((TXT
+					 ("Failed to allocate RX buffer.\n")));
+				return;
+			}
+			if (unused_bytes > 0) {
+				/* Copy the remaining bytes to the end of
+				   alingment block (256 bytes) so next read
+				   will be alligned. */
+				align_block =
+				    (((unused_bytes + SPI_PACKET_SIZE -
+				       1) >> SPI_PACKET_SIZE_BITS) <<
+				     SPI_PACKET_SIZE_BITS);
+				memset(tmp_buf->ptr, 0,
+				       align_block - unused_bytes);
+				memcpy((char *)tmp_buf->ptr +
+				       (align_block - unused_bytes),
+				       (char *)buf->ptr + offset + len -
+				       unused_bytes, unused_bytes);
+				len = align_block;
+			}
+			offset = 0;
+			buf = tmp_buf;
+		}
+		if (tx_bytes <= 0) {
+			txbuf = 0;
+			tx_bytes = 0;
+		}
+		if (bytes_to_transfer < missing_bytes) {
+			bytes_to_transfer =
+			    (((missing_bytes + SPI_PACKET_SIZE -
+			       1) >> SPI_PACKET_SIZE_BITS) <<
+			     SPI_PACKET_SIZE_BITS);
+			PRN_DBG((TXT
+	("a message was found, adding bytes to transfer, txmsg %d, total %d\n")
+			, tx_bytes, bytes_to_transfer));
+		}
+	}
+	dev->cb.free_rx_buf(dev->context, buf);
+}
+
+int smsspicommon_init(struct spi_dev *dev, void *context, void *phy_context,
+		      spi_dev_cb_st *cb)
+{
+	PRN_DBG((TXT("entering.\n")));
+	if (cb->transfer_data_cb == 0 ||
+	    cb->msg_found_cb == 0 ||
+	    cb->allocate_rx_buf == 0 || cb->free_rx_buf == 0) {
+		PRN_ERR((TXT("Invalid input parameters of init routine.\n")));
+		return -1;
+	}
+	dev->context = context;
+	dev->phy_context = phy_context;
+	memcpy(&dev->cb, cb, sizeof(spi_dev_cb_st));
+	dev->rxState = RxsWait_a5;
+	PRN_DBG((TXT("exiting.\n")));
+	return 0;
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.c~ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.c~
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.c~	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.c~	2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,326 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#include "smsspicommon.h"
+#include "smsdbg_prn.h"
+
+static int smsspi_common_find_msg(struct spi_dev *dev, rx_buffer_st * buf,
+				  int offset, int len, int *unused_bytes)
+{
+	int i, missing_bytes;
+	int recieved_bytes, padded_msg_len;
+	int align_fix;
+	char *ptr = (char *)buf->ptr + offset;
+
+	PRN_DBG((TXT("entering with %d bytes.\n"), len));
+	missing_bytes = 0;
+	for (i = 0; i < len; i++, ptr++) {
+		switch (dev->rxState) {
+		case RxsWait_a5:
+			dev->rxState =
+			    ((*ptr & 0xff) == 0xa5) ? RxsWait_5a : RxsWait_a5;
+			dev->rxPacket.msg_offset =
+			    (unsigned long)ptr - (unsigned long)buf->ptr + 4;
+			break;
+		case RxsWait_5a:
+			dev->rxState =
+			    ((*ptr & 0xff) == 0x5a) ? RxsWait_e7 : RxsWait_a5;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsWait_e7:
+			dev->rxState =
+			    ((*ptr & 0xff) == 0xe7) ? RxsWait_7e : RxsWait_a5;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsWait_7e:
+			dev->rxState =
+			    ((*ptr & 0xff) == 0x7e) ? RxsTypeH : RxsWait_a5;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsTypeH:
+			dev->rxPacket.msg_buf = buf;
+			dev->rxPacket.msg_offset =
+			    (unsigned long)ptr - (unsigned long)buf->ptr;
+			dev->rxState = RxsTypeL;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsTypeL:
+			dev->rxState = RxsGetSrcId;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsGetSrcId:
+			dev->rxState = RxsGetDstId;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsGetDstId:
+			dev->rxState = RxsGetLenL;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsGetLenL:
+			dev->rxState = RxsGetLenH;
+			dev->rxPacket.msg_len = (*ptr & 0xff);
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsGetLenH:
+			dev->rxState = RxsFlagsL;
+			dev->rxPacket.msg_len += (*ptr & 0xff) << 8;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsFlagsL:
+			dev->rxState = RxsFlagsH;
+			dev->rxPacket.msg_flags = (*ptr & 0xff);
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsFlagsH:
+			dev->rxState = RxsData;
+			dev->rxPacket.msg_flags += (*ptr & 0xff) << 8;
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		case RxsData:
+			recieved_bytes =
+			    len + offset - dev->rxPacket.msg_offset;
+			padded_msg_len =
+			    ((dev->rxPacket.msg_len + 4 + SPI_PACKET_SIZE -
+			      1) >> SPI_PACKET_SIZE_BITS) <<
+			    SPI_PACKET_SIZE_BITS;
+			if (recieved_bytes < padded_msg_len) {
+				*unused_bytes = 0;
+				return padded_msg_len - recieved_bytes;
+			}
+			dev->rxState = RxsWait_a5;
+			if (dev->cb.msg_found_cb) {
+				align_fix = 0;
+				if (dev->rxPacket.
+				    msg_flags & MSG_HDR_FLAG_SPLIT_MSG_HDR) {
+					align_fix =
+					    (dev->rxPacket.
+					     msg_flags >> 8) & 0x3;
+					if (align_fix) {
+					/* The FW alligned the message data
+					therefore - alligment bytes should be
+					thrown away. Throw the aligment bytes
+					by moving the header ahead over the
+					alligment bytes. */
+						ptr =
+						    (char *)dev->rxPacket.
+						    msg_buf->ptr +
+						    dev->rxPacket.msg_offset;
+
+						/* Restore header to original
+						state before alignment changes
+						*/
+						u16 length =
+						    (ptr[5] << 8) | ptr[4];
+						length -= align_fix;
+						ptr[5] = length >> 8;
+						ptr[4] = length & 0xff;
+						/* Zero alignment flags */
+						ptr[7] &= 0xfc;
+
+						for (i = MSG_HDR_LEN - 1;
+						     i >= 0; i--) {
+							ptr[i + align_fix] =
+							    ptr[i];
+						}
+						dev->rxPacket.msg_offset +=
+						    align_fix;
+					}
+				}
+
+				PRN_DBG((TXT
+				("Msg found and sent to callback func.\n")));
+				dev->cb.msg_found_cb(dev->context,
+						     dev->rxPacket.msg_buf,
+						     dev->rxPacket.msg_offset,
+						     dev->rxPacket.msg_len -
+						     align_fix);
+				*unused_bytes =
+				    len + offset - dev->rxPacket.msg_offset -
+				    dev->rxPacket.msg_len;
+				if (*unused_bytes == 0)
+					*unused_bytes = -1;
+				return 0;
+			} else {
+				PRN_DBG((TXT
+		 ("Msg found but no callback. therefore - thrown away.\n")));
+			}
+			PRN_DBG((TXT("state %d.\n"), dev->rxState));
+			break;
+		}
+	}
+
+	if (dev->rxState == RxsWait_a5) {
+		*unused_bytes = 0;
+		return 0;
+	} else {
+		/* Workaround to corner case: if the last byte of the buffer
+		is "a5" (first byte of the preamble), the host thinks it should
+		send another 256 bytes.  In case the a5 is the firmware
+		underflow byte, this will cause an infinite loop, so we check
+		for this case explicity. */
+		if ((dev->rxState == RxsWait_5a) && (*(ptr - 2) == 0xa5)) {
+			dev->rxState = RxsWait_a5;
+			*unused_bytes = 0;
+			return 0;
+		}
+
+		if (dev->rxPacket.msg_offset >= (SPI_PACKET_SIZE + 4))
+			/* adding 4 for the preamble. */
+		{		/*The packet will be copied to a new buffer
+				   and rescaned by the state machine */
+			*unused_bytes = dev->rxState - RxsWait_a5;
+			dev->rxState = RxsWait_a5;
+			dev->cb.free_rx_buf(dev->context, buf);
+			return 0;
+		} else {
+			/* report missing bytes and continue
+			   with message scan. */
+			*unused_bytes = 0;
+			return SPI_PACKET_SIZE;
+		}
+	}
+}
+
+void smsspi_common_transfer_msg(struct spi_dev *dev, struct spi_msg *txmsg,
+				int padding_allowed)
+{
+	int len, bytes_to_transfer;
+	unsigned long tx_phy_addr;
+	int missing_bytes, tx_bytes;
+	int offset, unused_bytes;
+	int align_block;
+	char *txbuf;
+	rx_buffer_st * buf, *tmp_buf;
+
+	len = 0;
+	if (!dev->cb.transfer_data_cb) {
+		PRN_ERR((TXT
+		("function called while module is not initialized.\n")));
+		return;
+	}
+	if (txmsg == 0) {
+		bytes_to_transfer = SPI_PACKET_SIZE;
+		txbuf = 0;
+		tx_phy_addr = 0;
+		tx_bytes = 0;
+	} else {
+		tx_bytes = txmsg->len;
+		if (padding_allowed)
+			bytes_to_transfer =
+			    (((tx_bytes + SPI_PACKET_SIZE -
+			       1) >> SPI_PACKET_SIZE_BITS) <<
+			     SPI_PACKET_SIZE_BITS);
+		else
+			bytes_to_transfer = (((tx_bytes + 3) >> 2) << 2);
+		txbuf = txmsg->buf;
+		tx_phy_addr = txmsg->buf_phy_addr;
+	}
+	offset = 0;
+	unused_bytes = 0;
+	buf =
+	    dev->cb.allocate_rx_buf(dev->context,
+				    RX_PACKET_SIZE + SPI_PACKET_SIZE);
+	if (!buf) {
+		PRN_ERR((TXT("Failed to allocate RX buffer.\n")));
+		return;
+	}
+	while (bytes_to_transfer || unused_bytes) {
+		if ((unused_bytes <= 0) && (bytes_to_transfer > 0)) {
+			len = min(bytes_to_transfer, RX_PACKET_SIZE);
+			PRN_DBG((TXT("transfering block of %d bytes\n"), len));
+			dev->cb.transfer_data_cb(dev->phy_context, txbuf,
+						 tx_phy_addr,
+						 (char *)buf->ptr + offset,
+						 buf->phy_addr + offset, len);
+		}
+		missing_bytes =
+		    smsspi_common_find_msg(dev, buf, offset, len,
+					   &unused_bytes);
+		if (bytes_to_transfer)
+			bytes_to_transfer -= len;
+
+		if (tx_bytes)
+			tx_bytes -= len;
+
+		if (missing_bytes)
+			offset += len;
+
+		if (unused_bytes) {
+			tmp_buf =
+			    dev->cb.allocate_rx_buf(dev->context,
+						    RX_PACKET_SIZE);
+			if (!tmp_buf) {
+				PRN_ERR((TXT
+					 ("Failed to allocate RX buffer.\n")));
+				return;
+			}
+			if (unused_bytes > 0) {
+				/* Copy the remaining bytes to the end of
+				   alingment block (256 bytes) so next read
+				   will be alligned. */
+				align_block =
+				    (((unused_bytes + SPI_PACKET_SIZE -
+				       1) >> SPI_PACKET_SIZE_BITS) <<
+				     SPI_PACKET_SIZE_BITS);
+				memset(tmp_buf->ptr, 0,
+				       align_block - unused_bytes);
+				memcpy((char *)tmp_buf->ptr +
+				       (align_block - unused_bytes),
+				       (char *)buf->ptr + offset + len -
+				       unused_bytes, unused_bytes);
+				len = align_block;
+			}
+			offset = 0;
+			buf = tmp_buf;
+		}
+		if (tx_bytes <= 0) {
+			txbuf = 0;
+			tx_bytes = 0;
+		}
+		if (bytes_to_transfer < missing_bytes) {
+			bytes_to_transfer =
+			    (((missing_bytes + SPI_PACKET_SIZE -
+			       1) >> SPI_PACKET_SIZE_BITS) <<
+			     SPI_PACKET_SIZE_BITS);
+			PRN_DBG((TXT
+				 ("a message was found, adding bytes to transfer, txmsg %d, total %d\n"),
+				 tx_bytes, bytes_to_transfer));
+		}
+	}
+	dev->cb.free_rx_buf(dev->context, buf);
+}
+
+int smsspicommon_init(struct spi_dev *dev, void *context, void *phy_context,
+		      spi_dev_cb_st *cb)
+{
+	PRN_DBG((TXT("entering.\n")));
+	if (cb->transfer_data_cb == 0 ||
+	    cb->msg_found_cb == 0 ||
+	    cb->allocate_rx_buf == 0 || cb->free_rx_buf == 0) {
+		PRN_ERR((TXT("Invalid input parameters of init routine.\n")));
+		return -1;
+	}
+	dev->context = context;
+	dev->phy_context = phy_context;
+	memcpy(&dev->cb, cb, sizeof(spi_dev_cb_st));
+	dev->rxState = RxsWait_a5;
+	PRN_DBG((TXT("exiting.\n")));
+	return 0;
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.h v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.h
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.h	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.h	2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,96 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#ifndef _SMS_SPI_COMMON_H_
+#define _SMS_SPI_COMMON_H_
+
+#define RX_PACKET_SIZE  		0x1000
+#define SPI_PACKET_SIZE_BITS		8
+#define SPI_PACKET_SIZE 		(1<<SPI_PACKET_SIZE_BITS)
+#define SPI_MAX_CTRL_MSG_SIZE		0x100
+
+#define MSG_HDR_FLAG_SPLIT_MSG_HDR	0x0004
+#define MSG_HDR_LEN			8
+
+enum _spi_rx_state {
+	RxsWait_a5 = 0,
+	RxsWait_5a,
+	RxsWait_e7,
+	RxsWait_7e,
+	RxsTypeH,
+	RxsTypeL,
+	RxsGetSrcId,
+	RxsGetDstId,
+	RxsGetLenL,
+	RxsGetLenH,
+	RxsFlagsL,
+	RxsFlagsH,
+	RxsData
+} spi_rx_state;
+
+struct {
+	void *ptr;
+	unsigned long phy_addr;
+} rx_buffer_st;
+
+struct _rx_packet_request {
+	rx_buffer_st *msg_buf;
+	int msg_offset;
+	int msg_len;
+	int msg_flags;
+} rx_packet_request;
+
+struct {
+	void (*transfer_data_cb) (void *context, unsigned char *, unsigned long,
+				  unsigned char *, unsigned long, int);
+	void (*msg_found_cb) (void *, void *, int, int);
+	rx_buffer_st *(*allocate_rx_buf) (void *, int);
+	void (*free_rx_buf) (void *, rx_buffer_st *);
+} spi_dev_cb_st;
+
+struct spi_dev {
+	void *context;
+	void *phy_context;
+	spi_dev_cb_st cb;
+	char *rxbuf;
+	spi_rx_state rxState;
+	rx_packet_request rxPacket;
+	char *internal_tx_buf;
+} spi_dev_st;
+
+struct spi_msg {
+	char *buf;
+	unsigned long buf_phy_addr;
+	int len;
+} spi_msg_st;
+
+void smsspi_common_transfer_msg(struct spi_dev *dev, struct spi_msg *txmsg,
+				int padding_allowed);
+int smsspicommon_init(struct spi_dev *dev, void *contex, void *phy_context,
+		      spi_dev_cb_st *cb);
+
+#if defined HEXDUMP_DEBUG && defined SPIBUS_DEBUG
+/*! dump a human readable print of a binary buffer */
+void smsspi_khexdump(char *buf, int len);
+#else
+#define smsspi_khexdump(buf, len)
+#endif
+
+#endif /*_SMS_SPI_COMMON_H_*/
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspilog.c v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspilog.c
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspilog.c	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspilog.c	2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,446 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+/*!
+	\file	spibusdrv.c
+
+	\brief	spi bus driver module
+
+	This file contains implementation of the spi bus driver.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include "smscoreapi.h"
+#include "smsdbg_prn.h"
+#include "smsspicommon.h"
+#include "smsspiphy.h"
+
+#define SMS_INTR_PIN			16  /* 0 for nova sip, 26 for vega */
+#define TX_BUFFER_SIZE			0x200
+#define RX_BUFFER_SIZE			(0x1000 + SPI_PACKET_SIZE + 0x100)
+#define NUM_RX_BUFFERS			72
+
+struct {
+	struct spi_dev dev;
+	void *phy_dev;
+
+	struct completion write_operation;
+	struct list_head tx_queue;
+	int allocatedPackets;
+	int padding_allowed;
+	char *rxbuf;
+	dma_addr_t rxbuf_phy_addr;
+
+	struct smscore_device_t *coredev;
+	struct list_head txqueue;
+	char *txbuf;
+	dma_addr_t txbuf_phy_addr;
+} spi_device_st;
+
+struct _smsspi_txmsg {
+	struct list_head node;	/*! internal management */
+	void *buffer;
+	size_t size;
+	int alignment;
+	int add_preamble;
+	struct completion completion;
+	void (*prewrite) (void *);
+	void (*postwrite) (void *);
+} smsspi_txmsg_t;
+
+spi_device_st *spi_dev;
+
+static void spi_worker_thread(void *arg);
+static DECLARE_WORK(spi_work_queue, (void *)spi_worker_thread);
+static u8 smsspi_preamble[] = { 0xa5, 0x5a, 0xe7, 0x7e };
+static u8 smsspi_startup[] = { 0, 0, 0xde, 0xc1, 0xa5, 0x51, 0xf1, 0xed };
+static u32 default_type = SMS_NOVA_A0;
+static u32 intr_pin = SMS_INTR_PIN;
+
+module_param(default_type, int, 0644);
+MODULE_PARM_DESC(default_type, "default board type.");
+
+module_param(intr_pin, int, 0644);
+MODULE_PARM_DESC(intr_pin, "interrupt pin number.");
+
+/******************************************/
+static void spi_worker_thread(void *arg)
+{
+	spi_device_st *spi_device = spi_dev;
+	smsspi_txmsg_t *msg = NULL;
+	spi_msg_st txmsg;
+
+	PDEBUG("worker start\n");
+	do {
+		/* do we have a msg to write ? */
+		if (!msg && !list_empty(&spi_device->txqueue))
+			msg =
+			    (smsspi_txmsg_t *) list_entry(spi_device->txqueue.
+							  next, smsspi_txmsg_t,
+							  node);
+
+		if (msg) {
+			if (msg->add_preamble) {
+				txmsg.len =
+				    min(msg->size + sizeof(smsspi_preamble),
+					(size_t) TX_BUFFER_SIZE);
+				txmsg.buf = spi_device->txbuf;
+				txmsg.buf_phy_addr = spi_device->txbuf_phy_addr;
+				memcpy(txmsg.buf, smsspi_preamble,
+				       sizeof(smsspi_preamble));
+				memcpy(&txmsg.buf[sizeof(smsspi_preamble)],
+				       msg->buffer,
+				       txmsg.len - sizeof(smsspi_preamble));
+				msg->add_preamble = 0;
+				msg->buffer +=
+				    txmsg.len - sizeof(smsspi_preamble);
+				msg->size -=
+				    txmsg.len - sizeof(smsspi_preamble);
+				/* zero out the rest of aligned buffer */
+				memset(&txmsg.buf[txmsg.len], 0,
+				       TX_BUFFER_SIZE - txmsg.len);
+				smsspi_common_transfer_msg(&spi_device->dev,
+							   &txmsg, 1);
+			} else {
+				txmsg.len =
+				    min(msg->size, (size_t) TX_BUFFER_SIZE);
+				txmsg.buf = spi_device->txbuf;
+				txmsg.buf_phy_addr = spi_device->txbuf_phy_addr;
+				memcpy(txmsg.buf, msg->buffer, txmsg.len);
+
+				msg->buffer += txmsg.len;
+				msg->size -= txmsg.len;
+				/* zero out the rest of aligned buffer */
+				memset(&txmsg.buf[txmsg.len], 0,
+				       TX_BUFFER_SIZE - txmsg.len);
+				smsspi_common_transfer_msg(&spi_device->dev,
+							   &txmsg, 0);
+			}
+
+		} else {
+			smsspi_common_transfer_msg(&spi_device->dev, NULL, 1);
+		}
+
+		/* if there was write, have we finished ? */
+		if (msg && !msg->size) {
+			/* call postwrite call back */
+			if (msg->postwrite)
+				msg->postwrite(spi_device);
+
+			list_del(&msg->node);
+			complete(&msg->completion);
+			msg = NULL;
+		}
+		/* if there was read, did we read anything ? */
+
+	} while (!list_empty(&spi_device->txqueue) || msg);
+
+	PDEBUG("worker end\n");
+
+}
+
+static void msg_found(void *context, void *buf, int offset, int len)
+{
+	spi_device_st *spi_device = (spi_device_st *) context;
+	struct smscore_buffer_t *cb =
+	    (struct smscore_buffer_t
+	     *)(container_of(buf, struct smscore_buffer_t, p));
+
+	PDEBUG("entering\n");
+	cb->offset = offset;
+	cb->size = len;
+	/* PERROR ("buffer %p is sent back to core databuf=%p,
+		offset=%d.\n", cb, cb->p, cb->offset); */
+	smscore_onresponse(spi_device->coredev, cb);
+
+	PDEBUG("exiting\n");
+
+}
+
+static void smsspi_int_handler(void *context)
+{
+	spi_device_st *spi_device = (spi_device_st *) context;
+	PDEBUG("interrupt\n");
+	PREPARE_WORK(&spi_work_queue, (void *)spi_worker_thread);
+	spi_device->padding_allowed = 1;
+	schedule_work(&spi_work_queue);
+}
+
+static int smsspi_queue_message_and_wait(spi_device_st *spi_device,
+					 smsspi_txmsg_t *msg)
+{
+	init_completion(&msg->completion);
+	list_add_tail(&msg->node, &spi_device->txqueue);
+	schedule_work(&spi_work_queue);
+	wait_for_completion(&msg->completion);
+
+	return 0;
+}
+
+static int smsspi_preload(void *context)
+{
+	smsspi_txmsg_t msg;
+	spi_device_st *spi_device = (spi_device_st *) context;
+
+	prepareForFWDnl(spi_device->phy_dev);
+	PDEBUG("Sending SPI init sequence\n");
+	msg.buffer = smsspi_startup;
+	msg.size = sizeof(smsspi_startup);
+	msg.alignment = 4;
+	msg.add_preamble = 0;
+	msg.prewrite = NULL;	/* smsspiphy_reduce_clock; */
+	msg.postwrite = NULL;
+
+	return smsspi_queue_message_and_wait(context, &msg);
+}
+
+static int smsspi_postload(void *context)
+{
+	struct _Msg {
+		struct SmsMsgHdr_ST hdr;
+		u32 data[3];
+	} Msg = {
+		{
+		MSG_SMS_SPI_INT_LINE_SET_REQ, 0, HIF_TASK,
+			    sizeof(struct _Msg), 0}, {
+		0, intr_pin, 0}
+	};
+	spi_device_st *spi_device = (spi_device_st *) context;
+	smsspi_txmsg_t msg;
+
+	PDEBUG("Sending SPI Set Interrupt command sequence\n");
+	fwDnlComplete(spi_device->phy_dev, 0);
+	msg.buffer = &Msg;
+	msg.size = sizeof(Msg);
+	msg.alignment = SPI_PACKET_SIZE;
+	msg.add_preamble = 1;
+	msg.prewrite = NULL;
+	msg.postwrite = NULL;	/* smsspiphy_restore_clock; */
+
+	return smsspi_queue_message_and_wait(context, &msg);
+}
+
+static int smsspi_write(void *context, void *txbuf, size_t len)
+{
+	smsspi_txmsg_t msg;
+
+	msg.buffer = txbuf;
+	msg.size = len;
+	msg.prewrite = NULL;
+	msg.postwrite = NULL;
+
+	if (len > 0x1000) {
+		/* The FW is the only long message. Do not add preamble,
+		and do not padd it */
+		msg.alignment = 4;
+		msg.add_preamble = 0;
+		msg.prewrite = smschipreset;
+	} else {
+		msg.alignment = SPI_PACKET_SIZE;
+		msg.add_preamble = 1;
+	}
+	PDEBUG("Writing message to  SPI.\n");
+	PDEBUG("msg hdr: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x.\n",
+	       ((u8 *) txbuf)[0], ((u8 *) txbuf)[1], ((u8 *) txbuf)[2],
+	       ((u8 *) txbuf)[3], ((u8 *) txbuf)[4], ((u8 *) txbuf)[5],
+	       ((u8 *) txbuf)[6], ((u8 *) txbuf)[7]);
+	return smsspi_queue_message_and_wait(context, &msg);
+}
+
+rx_buffer_st *allocate_rx_buf(void *context, int size)
+{
+	struct smscore_buffer_t *buf;
+	spi_device_st *spi_device = (spi_device_st *) context;
+	if (size > RX_BUFFER_SIZE) {
+		PERROR("Requested size is bigger than max buffer size.\n");
+		return NULL;
+	}
+	buf = smscore_getbuffer(spi_device->coredev);
+	PDEBUG("Recieved Rx buf %p physical 0x%x (contained in %p)\n", buf->p,
+	       buf->phys, buf);
+
+	/* note: this is not mistake! the rx_buffer_st is identical to part of
+	   smscore_buffer_t and we return the address of the start of the
+	   identical part */
+	return (rx_buffer_st *) &buf->p;
+}
+
+static void free_rx_buf(void *context, rx_buffer_st *buf)
+{
+	spi_device_st *spi_device = (spi_device_st *) context;
+	struct smscore_buffer_t *cb =
+	    (struct smscore_buffer_t
+	     *)(container_of(((void *)buf), struct smscore_buffer_t, p));
+	PDEBUG("buffer %p is released.\n", cb);
+	smscore_putbuffer(spi_device->coredev, cb);
+}
+
+/*! Release device STUB
+
+\param[in]	dev:		device control block
+\return		void
+*/
+static void smsspi_release(struct device *dev)
+{
+	PDEBUG("nothing to do\n");
+	/* Nothing to release */
+}
+
+static struct platform_device smsspi_device = {
+	.name = "smsspi",
+	.id = 1,
+	.dev = {
+		.release = smsspi_release,
+		},
+};
+
+int smsspi_register(void)
+{
+	struct smsdevice_params_t params;
+	int ret;
+	spi_device_st *spi_device;
+	spi_dev_cb_st common_cb;
+
+	PDEBUG("entering \n");
+
+	spi_device =
+	    kmalloc(sizeof(spi_device_st), GFP_KERNEL);
+	spi_dev = spi_device;
+
+	INIT_LIST_HEAD(&spi_device->txqueue);
+
+	ret = platform_device_register(&smsspi_device);
+	if (ret < 0) {
+		PERROR("platform_device_register failed\n");
+		return ret;
+	}
+
+	spi_device->txbuf =
+	    dma_alloc_coherent(NULL, TX_BUFFER_SIZE,
+			       &spi_device->txbuf_phy_addr,
+			       GFP_KERNEL | GFP_DMA);
+	if (!spi_device->txbuf) {
+		printk(KERN_INFO "%s dma_alloc_coherent(...) failed\n",
+		       __func__);
+		ret = -ENOMEM;
+		goto txbuf_error;
+	}
+
+	spi_device->phy_dev =
+	    smsspiphy_init(NULL, smsspi_int_handler, &spi_device);
+	if (spi_device->phy_dev == 0) {
+		printk(KERN_INFO "%s smsspiphy_init(...) failed\n", __func__);
+		goto phy_error;
+	}
+
+	common_cb.allocate_rx_buf = allocate_rx_buf;
+	common_cb.free_rx_buf = free_rx_buf;
+	common_cb.msg_found_cb = msg_found;
+	common_cb.transfer_data_cb = smsspibus_xfer;
+
+	ret =
+	    smsspicommon_init(&spi_device->dev, spi_device, spi_device->phy_dev,
+			      &common_cb);
+	if (ret) {
+		printk(KERN_INFO "%s smsspiphy_init(...) failed\n", __func__);
+		goto common_error;
+	}
+
+	/* register in smscore */
+	memset(&params, 0, sizeof(params));
+	params.context = spi_device;
+	params.device = &smsspi_device.dev;
+	params.buffer_size = RX_BUFFER_SIZE;
+	params.num_buffers = NUM_RX_BUFFERS;
+	params.flags = SMS_DEVICE_NOT_READY;
+	params.sendrequest_handler = smsspi_write;
+	strcpy(params.devpath, "spi");
+	params.device_type = default_type;
+
+	if (0) {
+		/* device family */
+		/* params.setmode_handler = smsspi_setmode; */
+	} else {
+		params.flags =
+		    SMS_DEVICE_FAMILY2 | SMS_DEVICE_NOT_READY |
+		    SMS_ROM_NO_RESPONSE;
+		params.preload_handler = smsspi_preload;
+		params.postload_handler = smsspi_postload;
+	}
+
+	ret = smscore_register_device(&params, &spi_device->coredev);
+	if (ret < 0) {
+		printk(KERN_INFO "%s smscore_register_device(...) failed\n",
+		       __func__);
+		goto reg_device_error;
+	}
+
+	ret = smscore_start_device(spi_device->coredev);
+	if (ret < 0) {
+		printk(KERN_INFO "%s smscore_start_device(...) failed\n",
+		       __func__);
+		goto start_device_error;
+	}
+
+	PDEBUG("exiting\n");
+	return 0;
+
+start_device_error:
+	smscore_unregister_device(spi_device->coredev);
+
+reg_device_error:
+
+common_error:
+	smsspiphy_deinit(spi_device->phy_dev);
+
+phy_error:
+	dma_free_coherent(NULL, TX_BUFFER_SIZE, spi_device->txbuf,
+			  spi_device->txbuf_phy_addr);
+
+txbuf_error:
+	platform_device_unregister(&smsspi_device);
+
+	PDEBUG("exiting error %d\n", ret);
+
+	return ret;
+}
+
+void smsspi_unregister(void)
+{
+	spi_device_st *spi_device = spi_dev;
+	PDEBUG("entering\n");
+
+	/* stop interrupts */
+	smsspiphy_deinit(spi_device->phy_dev);
+	smscore_unregister_device(spi_device->coredev);
+
+	dma_free_coherent(NULL, TX_BUFFER_SIZE, spi_device->txbuf,
+			  spi_device->txbuf_phy_addr);
+
+	platform_device_unregister(&smsspi_device);
+	PDEBUG("exiting\n");
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspilog.c~ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspilog.c~
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspilog.c~	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspilog.c~	2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,446 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+/*!
+	\file	spibusdrv.c
+
+	\brief	spi bus driver module
+
+	This file contains implementation of the spi bus driver.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include "smscoreapi.h"
+#include "smsdbg_prn.h"
+#include "smsspicommon.h"
+#include "smsspiphy.h"
+
+#define SMS_INTR_PIN			16  /* 0 for nova sip, 26 for vega */
+#define TX_BUFFER_SIZE			0x200
+#define RX_BUFFER_SIZE			(0x1000 + SPI_PACKET_SIZE + 0x100)
+#define NUM_RX_BUFFERS			72
+
+struct {
+	struct spi_dev dev;
+	void *phy_dev;
+
+	struct completion write_operation;
+	struct list_head tx_queue;
+	int allocatedPackets;
+	int padding_allowed;
+	char *rxbuf;
+	dma_addr_t rxbuf_phy_addr;
+
+	struct smscore_device_t *coredev;
+	struct list_head txqueue;
+	char *txbuf;
+	dma_addr_t txbuf_phy_addr;
+} spi_device_st;
+
+struct _smsspi_txmsg {
+	struct list_head node;	/*! internal management */
+	void *buffer;
+	size_t size;
+	int alignment;
+	int add_preamble;
+	struct completion completion;
+	void (*prewrite) (void *);
+	void (*postwrite) (void *);
+} smsspi_txmsg_t;
+
+spi_device_st *spi_dev;
+
+static void spi_worker_thread(void *arg);
+static DECLARE_WORK(spi_work_queue, (void *)spi_worker_thread);
+static u8 smsspi_preamble[] = { 0xa5, 0x5a, 0xe7, 0x7e };
+static u8 smsspi_startup[] = { 0, 0, 0xde, 0xc1, 0xa5, 0x51, 0xf1, 0xed };
+static u32 default_type = SMS_NOVA_A0;
+static u32 intr_pin = SMS_INTR_PIN;
+
+module_param(default_type, int, 0644);
+MODULE_PARM_DESC(default_type, "default board type.");
+
+module_param(intr_pin, int, 0644);
+MODULE_PARM_DESC(intr_pin, "interrupt pin number.");
+
+/******************************************/
+static void spi_worker_thread(void *arg)
+{
+	spi_device_st *spi_device = spi_dev;
+	smsspi_txmsg_t *msg = NULL;
+	spi_msg_st txmsg;
+
+	PDEBUG("worker start\n");
+	do {
+		/* do we have a msg to write ? */
+		if (!msg && !list_empty(&spi_device->txqueue))
+			msg =
+			    (smsspi_txmsg_t *) list_entry(spi_device->txqueue.
+							  next, smsspi_txmsg_t,
+							  node);
+
+		if (msg) {
+			if (msg->add_preamble) {
+				txmsg.len =
+				    min(msg->size + sizeof(smsspi_preamble),
+					(size_t) TX_BUFFER_SIZE);
+				txmsg.buf = spi_device->txbuf;
+				txmsg.buf_phy_addr = spi_device->txbuf_phy_addr;
+				memcpy(txmsg.buf, smsspi_preamble,
+				       sizeof(smsspi_preamble));
+				memcpy(&txmsg.buf[sizeof(smsspi_preamble)],
+				       msg->buffer,
+				       txmsg.len - sizeof(smsspi_preamble));
+				msg->add_preamble = 0;
+				msg->buffer +=
+				    txmsg.len - sizeof(smsspi_preamble);
+				msg->size -=
+				    txmsg.len - sizeof(smsspi_preamble);
+				/* zero out the rest of aligned buffer */
+				memset(&txmsg.buf[txmsg.len], 0,
+				       TX_BUFFER_SIZE - txmsg.len);
+				smsspi_common_transfer_msg(&spi_device->dev,
+							   &txmsg, 1);
+			} else {
+				txmsg.len =
+				    min(msg->size, (size_t) TX_BUFFER_SIZE);
+				txmsg.buf = spi_device->txbuf;
+				txmsg.buf_phy_addr = spi_device->txbuf_phy_addr;
+				memcpy(txmsg.buf, msg->buffer, txmsg.len);
+
+				msg->buffer += txmsg.len;
+				msg->size -= txmsg.len;
+				/* zero out the rest of aligned buffer */
+				memset(&txmsg.buf[txmsg.len], 0,
+				       TX_BUFFER_SIZE - txmsg.len);
+				smsspi_common_transfer_msg(&spi_device->dev,
+							   &txmsg, 0);
+			}
+
+		} else {
+			smsspi_common_transfer_msg(&spi_device->dev, NULL, 1);
+		}
+
+		/* if there was write, have we finished ? */
+		if (msg && !msg->size) {
+			/* call postwrite call back */
+			if (msg->postwrite)
+				msg->postwrite(spi_device);
+
+			list_del(&msg->node);
+			complete(&msg->completion);
+			msg = NULL;
+		}
+		/* if there was read, did we read anything ? */
+
+	} while (!list_empty(&spi_device->txqueue) || msg);
+
+	PDEBUG("worker end\n");
+
+}
+
+static void msg_found(void *context, void *buf, int offset, int len)
+{
+	spi_device_st *spi_device = (spi_device_st *) context;
+	struct smscore_buffer_t *cb =
+	    (struct smscore_buffer_t
+	     *)(container_of(buf, struct smscore_buffer_t, p));
+
+	PDEBUG("entering\n");
+	cb->offset = offset;
+	cb->size = len;
+	/* PERROR ("buffer %p is sent back to core databuf=%p,
+		offset=%d.\n", cb, cb->p, cb->offset); */
+	smscore_onresponse(spi_device->coredev, cb);
+
+	PDEBUG("exiting\n");
+
+}
+
+static void smsspi_int_handler(void *context)
+{
+	spi_device_st *spi_device = (spi_device_st *) context;
+	PDEBUG("interrupt\n");
+	PREPARE_WORK(&spi_work_queue, (void *)spi_worker_thread);
+	spi_device->padding_allowed = 1;
+	schedule_work(&spi_work_queue);
+}
+
+static int smsspi_queue_message_and_wait(spi_device_st *spi_device,
+					 smsspi_txmsg_t *msg)
+{
+	init_completion(&msg->completion);
+	list_add_tail(&msg->node, &spi_device->txqueue);
+	schedule_work(&spi_work_queue);
+	wait_for_completion(&msg->completion);
+
+	return 0;
+}
+
+static int smsspi_preload(void *context)
+{
+	smsspi_txmsg_t msg;
+	spi_device_st *spi_device = (spi_device_st *) context;
+
+	prepareForFWDnl(spi_device->phy_dev);
+	PDEBUG("Sending SPI init sequence\n");
+	msg.buffer = smsspi_startup;
+	msg.size = sizeof(smsspi_startup);
+	msg.alignment = 4;
+	msg.add_preamble = 0;
+	msg.prewrite = NULL;	/* smsspiphy_reduce_clock; */
+	msg.postwrite = NULL;
+
+	return smsspi_queue_message_and_wait(context, &msg);
+}
+
+static int smsspi_postload(void *context)
+{
+	struct _Msg {
+		struct SmsMsgHdr_ST hdr;
+		u32 data[3];
+	} Msg = {
+		{
+		MSG_SMS_SPI_INT_LINE_SET_REQ, 0, HIF_TASK,
+			    sizeof(struct _Msg), 0}, {
+		0, intr_pin, 0}
+	};
+	spi_device_st *spi_device = (spi_device_st *) context;
+	smsspi_txmsg_t msg;
+
+	PDEBUG("Sending SPI Set Interrupt command sequence\n");
+	fwDnlComplete(spi_device->phy_dev, 0);
+	msg.buffer = &Msg;
+	msg.size = sizeof(Msg);
+	msg.alignment = SPI_PACKET_SIZE;
+	msg.add_preamble = 1;
+	msg.prewrite = NULL;
+	msg.postwrite = NULL;	/* smsspiphy_restore_clock; */
+
+	return smsspi_queue_message_and_wait(context, &msg);
+}
+
+static int smsspi_write(void *context, void *txbuf, size_t len)
+{
+	smsspi_txmsg_t msg;
+
+	msg.buffer = txbuf;
+	msg.size = len;
+	msg.prewrite = NULL;
+	msg.postwrite = NULL;
+
+	if (len > 0x1000) {
+		/* The FW is the only long message. Do not add preamble,
+		and do not padd it */
+		msg.alignment = 4;
+		msg.add_preamble = 0;
+		msg.prewrite = smschipreset;
+	} else {
+		msg.alignment = SPI_PACKET_SIZE;
+		msg.add_preamble = 1;
+	}
+	PDEBUG("Writing message to  SPI.\n");
+	PDEBUG("msg hdr: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x.\n",
+	       ((u8 *) txbuf)[0], ((u8 *) txbuf)[1], ((u8 *) txbuf)[2],
+	       ((u8 *) txbuf)[3], ((u8 *) txbuf)[4], ((u8 *) txbuf)[5],
+	       ((u8 *) txbuf)[6], ((u8 *) txbuf)[7]);
+	return smsspi_queue_message_and_wait(context, &msg);
+}
+
+rx_buffer_st *allocate_rx_buf(void *context, int size)
+{
+	struct smscore_buffer_t *buf;
+	spi_device_st *spi_device = (spi_device_st *) context;
+	if (size > RX_BUFFER_SIZE) {
+		PERROR("Requested size is bigger than max buffer size.\n");
+		return NULL;
+	}
+	buf = smscore_getbuffer(spi_device->coredev);
+	PDEBUG("Recieved Rx buf %p physical 0x%x (contained in %p)\n", buf->p,
+	       buf->phys, buf);
+
+	/* note: this is not mistake! the rx_buffer_st is identical to part of
+	   smscore_buffer_t and we return the address of the start of the
+	   identical part */
+	return (rx_buffer_st *) &buf->p;
+}
+
+static void free_rx_buf(void *context, rx_buffer_st *buf)
+{
+	spi_device_st *spi_device = (spi_device_st *) context;
+	struct smscore_buffer_t *cb =
+	    (struct smscore_buffer_t
+	     *)(container_of(((void *)buf), struct smscore_buffer_t, p));
+	PDEBUG("buffer %p is released.\n", cb);
+	smscore_putbuffer(spi_device->coredev, cb);
+}
+
+/*! Release device STUB
+
+\param[in]	dev:		device control block
+\return		void
+*/
+static void smsspi_release(struct device *dev)
+{
+	PDEBUG("nothing to do\n");
+	/* Nothing to release */
+}
+
+static struct platform_device smsspi_device = {
+	.name = "smsspi",
+	.id = 1,
+	.dev = {
+		.release = smsspi_release,
+		},
+};
+
+int smsspi_register(void)
+{
+	struct smsdevice_params_t params;
+	int ret;
+	spi_device_st *spi_device;
+	spi_dev_cb_st common_cb;
+
+	PDEBUG("entering \n");
+
+	spi_device =
+	    (spi_device_st *) kmalloc(sizeof(spi_device_st), GFP_KERNEL);
+	spi_dev = spi_device;
+
+	INIT_LIST_HEAD(&spi_device->txqueue);
+
+	ret = platform_device_register(&smsspi_device);
+	if (ret < 0) {
+		PERROR("platform_device_register failed\n");
+		return ret;
+	}
+
+	spi_device->txbuf =
+	    dma_alloc_coherent(NULL, TX_BUFFER_SIZE,
+			       &spi_device->txbuf_phy_addr,
+			       GFP_KERNEL | GFP_DMA);
+	if (!spi_device->txbuf) {
+		printk(KERN_INFO "%s dma_alloc_coherent(...) failed\n",
+		       __func__);
+		ret = -ENOMEM;
+		goto txbuf_error;
+	}
+
+	spi_device->phy_dev =
+	    smsspiphy_init(NULL, smsspi_int_handler, &spi_device);
+	if (spi_device->phy_dev == 0) {
+		printk(KERN_INFO "%s smsspiphy_init(...) failed\n", __func__);
+		goto phy_error;
+	}
+
+	common_cb.allocate_rx_buf = allocate_rx_buf;
+	common_cb.free_rx_buf = free_rx_buf;
+	common_cb.msg_found_cb = msg_found;
+	common_cb.transfer_data_cb = smsspibus_xfer;
+
+	ret =
+	    smsspicommon_init(&spi_device->dev, spi_device, spi_device->phy_dev,
+			      &common_cb);
+	if (ret) {
+		printk(KERN_INFO "%s smsspiphy_init(...) failed\n", __func__);
+		goto common_error;
+	}
+
+	/* register in smscore */
+	memset(&params, 0, sizeof(params));
+	params.context = spi_device;
+	params.device = &smsspi_device.dev;
+	params.buffer_size = RX_BUFFER_SIZE;
+	params.num_buffers = NUM_RX_BUFFERS;
+	params.flags = SMS_DEVICE_NOT_READY;
+	params.sendrequest_handler = smsspi_write;
+	strcpy(params.devpath, "spi");
+	params.device_type = default_type;
+
+	if (0) {
+		/* device family */
+		/* params.setmode_handler = smsspi_setmode; */
+	} else {
+		params.flags =
+		    SMS_DEVICE_FAMILY2 | SMS_DEVICE_NOT_READY |
+		    SMS_ROM_NO_RESPONSE;
+		params.preload_handler = smsspi_preload;
+		params.postload_handler = smsspi_postload;
+	}
+
+	ret = smscore_register_device(&params, &spi_device->coredev);
+	if (ret < 0) {
+		printk(KERN_INFO "%s smscore_register_device(...) failed\n",
+		       __func__);
+		goto reg_device_error;
+	}
+
+	ret = smscore_start_device(spi_device->coredev);
+	if (ret < 0) {
+		printk(KERN_INFO "%s smscore_start_device(...) failed\n",
+		       __func__);
+		goto start_device_error;
+	}
+
+	PDEBUG("exiting\n");
+	return 0;
+
+start_device_error:
+	smscore_unregister_device(spi_device->coredev);
+
+reg_device_error:
+
+common_error:
+	smsspiphy_deinit(spi_device->phy_dev);
+
+phy_error:
+	dma_free_coherent(NULL, TX_BUFFER_SIZE, spi_device->txbuf,
+			  spi_device->txbuf_phy_addr);
+
+txbuf_error:
+	platform_device_unregister(&smsspi_device);
+
+	PDEBUG("exiting error %d\n", ret);
+
+	return ret;
+}
+
+void smsspi_unregister(void)
+{
+	spi_device_st *spi_device = spi_dev;
+	PDEBUG("entering\n");
+
+	/* stop interrupts */
+	smsspiphy_deinit(spi_device->phy_dev);
+	smscore_unregister_device(spi_device->coredev);
+
+	dma_free_coherent(NULL, TX_BUFFER_SIZE, spi_device->txbuf,
+			  spi_device->txbuf_phy_addr);
+
+	platform_device_unregister(&smsspi_device);
+	PDEBUG("exiting\n");
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy.h v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy.h
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy.h	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy.h	2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,36 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_SPI_PHY_H__
+#define __SMS_SPI_PHY_H__
+
+void smsspibus_xfer(void *context, unsigned char *txbuf,
+		    unsigned long txbuf_phy_addr, unsigned char *rxbuf,
+		    unsigned long rxbuf_phy_addr, int len);
+void *smsspiphy_init(void *context, void (*smsspi_interruptHandler) (void *),
+		     void *intr_context);
+void smsspiphy_deinit(void *context);
+void smschipreset(void *context);
+void WriteFWtoStellar(void *pSpiPhy, unsigned char *pFW, unsigned long Len);
+void prepareForFWDnl(void *pSpiPhy);
+void fwDnlComplete(void *context, int App);
+
+#endif /* __SMS_SPI_PHY_H__ */
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy_pxa.c v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy_pxa.c
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy_pxa.c	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy_pxa.c	2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,435 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#define PXA_310_LV
+
+#include <linux/kernel.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#ifdef PXA_310_LV
+#include <asm/arch/ssp.h>
+#include <asm/arch/mfp.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pxa3xx_gpio.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include "smsdbg_prn.h"
+
+#ifdef PXA_310_LV
+
+#define SSP_PORT 4
+#define SSP_CKEN CKEN_SSP4
+#define SMS_IRQ_GPIO MFP_PIN_GPIO93
+
+#if (SSP_PORT == 1)
+#define SDCMR_RX DRCMRRXSSDR
+#define SDCMR_TX DRCMRTXSSDR
+#else
+#if (SSP_PORT == 2)
+#define SDCMR_RX DRCMR15
+#define SDCMR_TX DRCMR16
+#else
+#if (SSP_PORT == 3)
+#define SDCMR_RX DRCMR66
+#define SDCMR_TX DRCMR67
+#else
+#if (SSP_PORT == 4)
+#define SDCMR_RX DRCMRRXSADR
+#define SDCMR_TX DRCMRTXSADR
+#endif
+#endif
+#endif
+#endif
+#else /*PXA_310_LV */
+#define SSP_PORT 1
+#define SDCMR_RX DRCMRRXSSDR
+#define SDCMR_TX DRCMRTXSSDR
+
+#endif /*PXA_310_LV */
+
+/* Macros defining physical layer behaviour*/
+#ifdef PXA_310_LV
+#define CLOCK_FACTOR 1
+#else /*PXA_310_LV */
+#define CLOCK_FACTOR 2
+#endif /*PXA_310_LV */
+
+/* Macros for coding reuse */
+
+/*! macro to align the divider to the proper offset in the register bits */
+#define CLOCK_DIVIDER(i)((i-1)<<8)	/* 1-4096 */
+
+/*! DMA related macros */
+#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
+#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
+
+#define SSP_TIMEOUT_SCALE (769)
+#define SSP_TIMEOUT(x) ((x*10000)/SSP_TIMEOUT_SCALE)
+
+#define SPI_PACKET_SIZE 256
+
+/* physical layer variables */
+/*! global bus data */
+struct {
+	struct ssp_dev sspdev;	/*!< ssp port configuration */
+	struct completion transfer_in_process;
+	void (*interruptHandler) (void *);
+	void *intr_context;
+	struct device *dev;	/*!< device model stuff */
+	int rx_dma_channel;
+	int tx_dma_channel;
+	int rx_buf_len;
+	int tx_buf_len;
+} spiphy_dev_st;
+
+/*!
+invert the endianness of a single 32it integer
+
+\param[in]		u: word to invert
+
+\return		the inverted word
+*/
+static inline u32 invert_bo(u32 u)
+{
+	return ((u & 0xff) << 24) | ((u & 0xff00) << 8) | ((u & 0xff0000) >> 8)
+		| ((u & 0xff000000) >> 24);
+}
+
+/*!
+invert the endianness of a data buffer
+
+\param[in]		buf: buffer to invert
+\param[in]		len: buffer length
+
+\return		the inverted word
+*/
+
+static int invert_endianness(char *buf, int len)
+{
+	int i;
+	u32 *ptr = (u32 *) buf;
+
+	len = (len + 3) / 4;
+	for (i = 0; i < len; i++, ptr++)
+		*ptr = invert_bo(*ptr);
+
+	return 4 * ((len + 3) & (~3));
+}
+
+/*! Map DMA buffers when request starts
+
+\return	error status
+*/
+static unsigned long dma_map_buf(spiphy_dev_st *spiphy_dev, char *buf, int len,
+				 int direction)
+{
+	unsigned long phyaddr;
+	/* map dma buffers */
+	if (!buf) {
+		PERROR(" NULL buffers to map\n");
+		return 0;
+	}
+	/* map buffer */
+	phyaddr = dma_map_single(spiphy_dev->dev, buf, len, direction);
+	if (dma_mapping_error(phyaddr)) {
+		PERROR("exiting  with error\n");
+		return 0;
+	}
+	return phyaddr;
+}
+
+static irqreturn_t spibus_interrupt(int irq, void *context)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	PDEBUG("recieved interrupt from device dev=%p.\n", context);
+	if (spiphy_dev->interruptHandler)
+		spiphy_dev->interruptHandler(spiphy_dev->intr_context);
+	return IRQ_HANDLED;
+
+}
+
+/*!	DMA controller callback - called only on BUS error condition
+
+\param[in]	channel: DMA channel with error
+\param[in]	data: Unused
+\param[in]	regs: Unused
+\return		void
+*/
+static void spibus_dma_handler(int channel, void *context)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+	PDEBUG("recieved interrupt from dma channel %d irq status %x.\n",
+	       channel, irq_status);
+	if (irq_status & DCSR_BUSERR) {
+		PERROR("bus error!!! resetting channel %d\n", channel);
+
+		DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+		DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL;
+	}
+	DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+	complete(&spiphy_dev->transfer_in_process);
+}
+
+void smsspibus_xfer(void *context, unsigned char *txbuf,
+		    unsigned long txbuf_phy_addr, unsigned char *rxbuf,
+		    unsigned long rxbuf_phy_addr, int len)
+{
+	/* DMA burst is 8 bytes, therefore we need tmp buffer that size. */
+	unsigned long tmp[2];
+	unsigned long txdma;
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+
+	/* program the controller */
+	if (txbuf)
+		invert_endianness(txbuf, len);
+
+	tmp[0] = -1;
+	tmp[1] = -1;
+
+	/* map RX buffer */
+
+	if (!txbuf)
+		txdma =
+		    dma_map_buf(spiphy_dev, (char *)tmp, sizeof(tmp),
+				DMA_TO_DEVICE);
+	else
+		txdma = txbuf_phy_addr;
+
+	init_completion(&spiphy_dev->transfer_in_process);
+	/* configure DMA Controller */
+	DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+	DSADR(spiphy_dev->rx_dma_channel) = __PREG(SSDR_P(SSP_PORT));
+	DTADR(spiphy_dev->rx_dma_channel) = rxbuf_phy_addr;
+	DCMD(spiphy_dev->rx_dma_channel) = DCMD_INCTRGADDR | DCMD_FLOWSRC
+	    | DCMD_WIDTH4 | DCMD_ENDIRQEN | DCMD_BURST8 | len;
+	PDEBUG("rx channel=%d, src=0x%x, dst=0x%x, cmd=0x%x\n",
+	       spiphy_dev->rx_dma_channel, __PREG(SSDR_P(SSP_PORT)),
+	       (unsigned int)rxbuf_phy_addr, DCMD(spiphy_dev->rx_dma_channel));
+	spiphy_dev->rx_buf_len = len;
+
+	DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL;
+	DTADR(spiphy_dev->tx_dma_channel) = __PREG(SSDR_P(SSP_PORT));
+	DSADR(spiphy_dev->tx_dma_channel) = txdma;
+	if (txbuf) {
+		DCMD(spiphy_dev->tx_dma_channel) =
+		    DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_WIDTH4
+		    /* | DCMD_ENDIRQEN */  | DCMD_BURST8 | len;
+		spiphy_dev->tx_buf_len = len;
+	} else {
+		DCMD(spiphy_dev->tx_dma_channel) = DCMD_FLOWTRG
+		    | DCMD_WIDTH4 /* | DCMD_ENDIRQEN */  | DCMD_BURST8 | len;
+		spiphy_dev->tx_buf_len = 4;
+	}
+
+	PDEBUG("tx channel=%d, src=0x%x, dst=0x%x, cmd=0x%x\n",
+	       spiphy_dev->tx_dma_channel, (unsigned int)txdma,
+	       __PREG(SSDR_P(SSP_PORT)), DCMD(spiphy_dev->tx_dma_channel));
+	/* DALGN - DMA ALIGNMENT REG. */
+	if (rxbuf_phy_addr & 0x7)
+		DALGN |= (1 << spiphy_dev->rx_dma_channel);
+	else
+		DALGN &= ~(1 << spiphy_dev->rx_dma_channel);
+	if (txdma & 0x7)
+		DALGN |= (1 << spiphy_dev->tx_dma_channel);
+	else
+		DALGN &= ~(1 << spiphy_dev->tx_dma_channel);
+
+	/* Start DMA controller */
+	DCSR(spiphy_dev->rx_dma_channel) |= DCSR_RUN;
+	DCSR(spiphy_dev->tx_dma_channel) |= DCSR_RUN;
+	PDEBUG("DMA running. wait for completion.\n");
+	wait_for_completion(&spiphy_dev->transfer_in_process);
+	PDEBUG("DMA complete.\n");
+	invert_endianness(rxbuf, len);
+}
+
+void smschipreset(void *context)
+{
+
+}
+
+void *smsspiphy_init(void *context, void (*smsspi_interruptHandler) (void *),
+		     void *intr_context)
+{
+	int ret;
+	spiphy_dev_st *spiphy_dev;
+	u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+	PDEBUG("entering\n");
+
+	spiphy_dev = kmalloc(sizeof(spiphy_dev_st), GFP_KERNEL);
+
+	ret = ssp_init(&spiphy_dev->sspdev, SSP_PORT, 0);
+	if (ret) {
+		PERROR("ssp_init failed. error %d", ret);
+		goto error_sspinit;
+	}
+#ifdef PXA_310_LV
+	pxa3xx_mfp_set_afds(SMS_IRQ_GPIO, MFP_AF0, MFP_DS03X);
+	pxa3xx_gpio_set_rising_edge_detect(SMS_IRQ_GPIO, 1);
+	pxa3xx_gpio_set_direction(SMS_IRQ_GPIO, GPIO_DIR_IN);
+#else /*PXA_310_LV */
+	/* receive input interrupts from the SMS 1000 on J32 pin 11 */
+	pxa_gpio_mode(22 | GPIO_IN);
+#endif /*PXA_310_LV */
+	speed = CLOCK_DIVIDER(CLOCK_FACTOR); /* clock divisor for this mode */
+	/* 32bit words in the fifo */
+	mode = SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS;
+	/* SSCR1 = flags */
+	flags = SSCR1_RxTresh(1) | SSCR1_TxTresh(1) | SSCR1_TSRE |
+	 SSCR1_RSRE | SSCR1_RIE | SSCR1_TRAIL;	/* | SSCR1_TIE */
+
+	ssp_config(&spiphy_dev->sspdev, mode, flags, psp_flags, speed);
+	ssp_disable(&(spiphy_dev->sspdev));
+#ifdef PXA_310_LV
+
+	pxa3xx_mfp_set_afds(MFP_PIN_GPIO95, MFP_AF1, MFP_DS03X);
+	pxa3xx_mfp_set_afds(MFP_PIN_GPIO96, MFP_AF1, MFP_DS03X);
+	pxa3xx_mfp_set_afds(MFP_PIN_GPIO97, MFP_AF1, MFP_DS03X);
+	pxa3xx_mfp_set_afds(MFP_PIN_GPIO98, MFP_AF1, MFP_DS03X);
+#else /*PXA_310_LV */
+	pxa_gpio_mode(GPIO23_SCLK_MD);
+	pxa_gpio_mode(GPIO24_SFRM_MD);
+	pxa_gpio_mode(GPIO25_STXD_MD);
+	pxa_gpio_mode(GPIO26_SRXD_MD);
+#endif /*PXA_310_LV */
+	/* setup the dma */
+	spiphy_dev->rx_dma_channel =
+	    pxa_request_dma("spibusdrv_rx", DMA_PRIO_HIGH, spibus_dma_handler,
+			    spiphy_dev);
+	if (spiphy_dev->rx_dma_channel < 0) {
+		ret = -EBUSY;
+		PERROR("Could not get RX DMA channel.\n");
+		goto error_rxdma;
+	}
+	spiphy_dev->tx_dma_channel =
+	    pxa_request_dma("spibusdrv_tx", DMA_PRIO_HIGH, spibus_dma_handler,
+			    spiphy_dev);
+	if (spiphy_dev->tx_dma_channel < 0) {
+		ret = -EBUSY;
+		PERROR("Could not get TX DMA channel.\n");
+		goto error_txdma;
+	}
+
+	SDCMR_RX = DRCMR_MAPVLD | spiphy_dev->rx_dma_channel;
+	SDCMR_TX = DRCMR_MAPVLD | spiphy_dev->tx_dma_channel;
+
+	PDEBUG("dma rx channel: %d, dma tx channel: %d\n",
+	       spiphy_dev->rx_dma_channel, spiphy_dev->tx_dma_channel);
+	/* enable the clock */
+
+	spiphy_dev->interruptHandler = smsspi_interruptHandler;
+	spiphy_dev->intr_context = intr_context;
+#ifdef PXA_310_LV
+	set_irq_type(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), IRQT_FALLING);
+	ret =
+	    request_irq(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), spibus_interrupt,
+			SA_INTERRUPT, "SMSSPI", spiphy_dev);
+#else /*PXA_310_LV */
+	set_irq_type(IRQ_GPIO(22), IRQT_FALLING);
+	ret =
+	    request_irq(IRQ_GPIO(22), spibus_interrupt, SA_INTERRUPT, "SMSSPI",
+			&(g_spidata.sspdev));
+#endif /*PXA_310_LV */
+	if (ret) {
+		PERROR("Could not get interrupt for SMS device. status =%d\n",
+		       ret);
+		goto error_irq;
+	}
+
+	ssp_enable(&(spiphy_dev->sspdev));
+	PDEBUG("exiting\n");
+	return spiphy_dev;
+error_irq:
+	if (spiphy_dev->tx_dma_channel >= 0)
+		pxa_free_dma(spiphy_dev->tx_dma_channel);
+
+error_txdma:
+	if (spiphy_dev->rx_dma_channel >= 0)
+		pxa_free_dma(spiphy_dev->rx_dma_channel);
+
+error_rxdma:
+	ssp_exit(&spiphy_dev->sspdev);
+error_sspinit:
+	PDEBUG("exiting on error\n");
+	return 0;
+}
+
+int smsspiphy_deinit(void *context)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	PDEBUG("entering\n");
+
+	/* disable the spi port */
+	ssp_flush(&spiphy_dev->sspdev);
+	ssp_disable(&spiphy_dev->sspdev);
+
+	/*  release DMA resources */
+	if (spiphy_dev->rx_dma_channel >= 0)
+		pxa_free_dma(spiphy_dev->rx_dma_channel);
+
+	if (spiphy_dev->tx_dma_channel >= 0)
+		pxa_free_dma(spiphy_dev->tx_dma_channel);
+
+	/* release Memory resources */
+#ifdef PXA_310_LV
+	free_irq(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), spiphy_dev);
+#else /*PXA_310_LV */
+	free_irq(IRQ_GPIO(22), &spiphy_dev->sspdev);
+#endif /*PXA_310_LV */
+	ssp_exit(&spiphy_dev->sspdev);
+	PDEBUG("exiting\n");
+	return 0;
+}
+
+void smsspiphy_set_config(spiphy_dev_st *spiphy_dev, int clock_divider)
+{
+	u32 mode, flags, speed, psp_flags = 0;
+	ssp_disable(&spiphy_dev->sspdev);
+	/* clock divisor for this mode. */
+	speed = CLOCK_DIVIDER(clock_divider);
+	/* 32bit words in the fifo */
+	mode = SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS;
+	flags = SSCR1_RxTresh(1) | SSCR1_TxTresh(1) | SSCR1_TSRE |
+		 SSCR1_RSRE | SSCR1_RIE | SSCR1_TRAIL;	/* | SSCR1_TIE */
+	ssp_config(&spiphy_dev->sspdev, mode, flags, psp_flags, speed);
+	ssp_enable(&spiphy_dev->sspdev);
+}
+
+void prepareForFWDnl(void *context)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	smsspiphy_set_config(spiphy_dev, 2);
+	msleep(100);
+}
+
+void fwDnlComplete(void *context, int App)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	smsspiphy_set_config(spiphy_dev, 1);
+	msleep(100);
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy_pxa.c~ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy_pxa.c~
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy_pxa.c~	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy_pxa.c~	2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,434 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#define PXA_310_LV
+
+#include <linux/kernel.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#ifdef PXA_310_LV
+#include <asm/arch/ssp.h>
+#include <asm/arch/mfp.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pxa3xx_gpio.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include "smsdbg_prn.h"
+
+#ifdef PXA_310_LV
+
+#define SSP_PORT 4
+#define SSP_CKEN CKEN_SSP4
+#define SMS_IRQ_GPIO MFP_PIN_GPIO93
+
+#if (SSP_PORT == 1)
+#define SDCMR_RX DRCMRRXSSDR
+#define SDCMR_TX DRCMRTXSSDR
+#else
+#if (SSP_PORT == 2)
+#define SDCMR_RX DRCMR15
+#define SDCMR_TX DRCMR16
+#else
+#if (SSP_PORT == 3)
+#define SDCMR_RX DRCMR66
+#define SDCMR_TX DRCMR67
+#else
+#if (SSP_PORT == 4)
+#define SDCMR_RX DRCMRRXSADR
+#define SDCMR_TX DRCMRTXSADR
+#endif
+#endif
+#endif
+#endif
+#else /*PXA_310_LV */
+#define SSP_PORT 1
+#define SDCMR_RX DRCMRRXSSDR
+#define SDCMR_TX DRCMRTXSSDR
+
+#endif /*PXA_310_LV */
+
+/* Macros defining physical layer behaviour*/
+#ifdef PXA_310_LV
+#define CLOCK_FACTOR 1
+#else /*PXA_310_LV */
+#define CLOCK_FACTOR 2
+#endif /*PXA_310_LV */
+
+/* Macros for coding reuse */
+
+/*! macro to align the divider to the proper offset in the register bits */
+#define CLOCK_DIVIDER(i)((i-1)<<8)	/* 1-4096 */
+
+/*! DMA related macros */
+#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
+#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
+
+#define SSP_TIMEOUT_SCALE (769)
+#define SSP_TIMEOUT(x) ((x*10000)/SSP_TIMEOUT_SCALE)
+
+#define SPI_PACKET_SIZE 256
+
+/* physical layer variables */
+/*! global bus data */
+struct {
+	struct ssp_dev sspdev;	/*!< ssp port configuration */
+	struct completion transfer_in_process;
+	void (*interruptHandler) (void *);
+	void *intr_context;
+	struct device *dev;	/*!< device model stuff */
+	int rx_dma_channel;
+	int tx_dma_channel;
+	int rx_buf_len;
+	int tx_buf_len;
+} spiphy_dev_st;
+
+/*!
+invert the endianness of a single 32it integer
+
+\param[in]		u: word to invert
+
+\return		the inverted word
+*/
+static inline u32 invert_bo(u32 u)
+{
+	return ((u & 0xff) << 24) | ((u & 0xff00) << 8) | ((u & 0xff0000) >> 8)
+		| ((u & 0xff000000) >> 24);
+}
+
+/*!
+invert the endianness of a data buffer
+
+\param[in]		buf: buffer to invert
+\param[in]		len: buffer length
+
+\return		the inverted word
+*/
+
+static int invert_endianness(char *buf, int len)
+{
+	int i;
+	u32 *ptr = (u32 *) buf;
+
+	len = (len + 3) / 4;
+	for (i = 0; i < len; i++, ptr++)
+		*ptr = invert_bo(*ptr);
+
+	return 4 * ((len + 3) & (~3));
+}
+
+/*! Map DMA buffers when request starts
+
+\return	error status
+*/
+static unsigned long dma_map_buf(spiphy_dev_st *spiphy_dev, char *buf, int len,
+				 int direction)
+{
+	unsigned long phyaddr;
+	/* map dma buffers */
+	if (!buf) {
+		PERROR(" NULL buffers to map\n");
+		return 0;
+	}
+	/* map buffer */
+	phyaddr = dma_map_single(spiphy_dev->dev, buf, len, direction);
+	if (dma_mapping_error(phyaddr)) {
+		PERROR("exiting  with error\n");
+		return 0;
+	}
+	return phyaddr;
+}
+
+static irqreturn_t spibus_interrupt(int irq, void *context)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	PDEBUG("recieved interrupt from device dev=%p.\n", context);
+	if (spiphy_dev->interruptHandler)
+		spiphy_dev->interruptHandler(spiphy_dev->intr_context);
+	return IRQ_HANDLED;
+
+}
+
+/*!	DMA controller callback - called only on BUS error condition
+
+\param[in]	channel: DMA channel with error
+\param[in]	data: Unused
+\param[in]	regs: Unused
+\return		void
+*/
+static void spibus_dma_handler(int channel, void *context)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+	PDEBUG("recieved interrupt from dma channel %d irq status %x.\n",
+	       channel, irq_status);
+	if (irq_status & DCSR_BUSERR) {
+		PERROR("bus error!!! resetting channel %d\n", channel);
+
+		DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+		DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL;
+	}
+	DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+	complete(&spiphy_dev->transfer_in_process);
+}
+
+void smsspibus_xfer(void *context, unsigned char *txbuf,
+		    unsigned long txbuf_phy_addr, unsigned char *rxbuf,
+		    unsigned long rxbuf_phy_addr, int len)
+{
+	/* DMA burst is 8 bytes, therefore we need tmp buffer that size. */
+	unsigned long tmp[2];
+	unsigned long txdma;
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+
+	/* program the controller */
+	if (txbuf)
+		invert_endianness(txbuf, len);
+
+	tmp[0] = -1;
+	tmp[1] = -1;
+
+	/* map RX buffer */
+
+	if (!txbuf)
+		txdma =
+		    dma_map_buf(spiphy_dev, (char *)tmp, sizeof(tmp),
+				DMA_TO_DEVICE);
+	else
+		txdma = txbuf_phy_addr;
+
+	init_completion(&spiphy_dev->transfer_in_process);
+	/* configure DMA Controller */
+	DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+	DSADR(spiphy_dev->rx_dma_channel) = __PREG(SSDR_P(SSP_PORT));
+	DTADR(spiphy_dev->rx_dma_channel) = rxbuf_phy_addr;
+	DCMD(spiphy_dev->rx_dma_channel) = DCMD_INCTRGADDR | DCMD_FLOWSRC
+	    | DCMD_WIDTH4 | DCMD_ENDIRQEN | DCMD_BURST8 | len;
+	PDEBUG("rx channel=%d, src=0x%x, dst=0x%x, cmd=0x%x\n",
+	       spiphy_dev->rx_dma_channel, __PREG(SSDR_P(SSP_PORT)),
+	       (unsigned int)rxbuf_phy_addr, DCMD(spiphy_dev->rx_dma_channel));
+	spiphy_dev->rx_buf_len = len;
+
+	DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL;
+	DTADR(spiphy_dev->tx_dma_channel) = __PREG(SSDR_P(SSP_PORT));
+	DSADR(spiphy_dev->tx_dma_channel) = txdma;
+	if (txbuf) {
+		DCMD(spiphy_dev->tx_dma_channel) =
+		    DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_WIDTH4
+		    /* | DCMD_ENDIRQEN */  | DCMD_BURST8 | len;
+		spiphy_dev->tx_buf_len = len;
+	} else {
+		DCMD(spiphy_dev->tx_dma_channel) = DCMD_FLOWTRG
+		    | DCMD_WIDTH4 /* | DCMD_ENDIRQEN */  | DCMD_BURST8 | len;
+		spiphy_dev->tx_buf_len = 4;
+	}
+
+	PDEBUG("tx channel=%d, src=0x%x, dst=0x%x, cmd=0x%x\n",
+	       spiphy_dev->tx_dma_channel, (unsigned int)txdma,
+	       __PREG(SSDR_P(SSP_PORT)), DCMD(spiphy_dev->tx_dma_channel));
+	/* DALGN - DMA ALIGNMENT REG. */
+	if (rxbuf_phy_addr & 0x7)
+		DALGN |= (1 << spiphy_dev->rx_dma_channel);
+	else
+		DALGN &= ~(1 << spiphy_dev->rx_dma_channel);
+	if (txdma & 0x7)
+		DALGN |= (1 << spiphy_dev->tx_dma_channel);
+	else
+		DALGN &= ~(1 << spiphy_dev->tx_dma_channel);
+
+	/* Start DMA controller */
+	DCSR(spiphy_dev->rx_dma_channel) |= DCSR_RUN;
+	DCSR(spiphy_dev->tx_dma_channel) |= DCSR_RUN;
+	PDEBUG("DMA running. wait for completion.\n");
+	wait_for_completion(&spiphy_dev->transfer_in_process);
+	PDEBUG("DMA complete.\n");
+	invert_endianness(rxbuf, len);
+}
+
+void smschipreset(void *context)
+{
+
+}
+
+void *smsspiphy_init(void *context, void (*smsspi_interruptHandler) (void *),
+		     void *intr_context)
+{
+	int ret;
+	spiphy_dev_st *spiphy_dev;
+	u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+	PDEBUG("entering\n");
+
+	spiphy_dev = kmalloc(sizeof(spiphy_dev_st), GFP_KERNEL);
+
+	ret = ssp_init(&spiphy_dev->sspdev, SSP_PORT, 0);
+	if (ret) {
+		PERROR("ssp_init failed. error %d", ret);
+		goto error_sspinit;
+	}
+#ifdef PXA_310_LV
+	pxa3xx_mfp_set_afds(SMS_IRQ_GPIO, MFP_AF0, MFP_DS03X);
+	pxa3xx_gpio_set_rising_edge_detect(SMS_IRQ_GPIO, 1);
+	pxa3xx_gpio_set_direction(SMS_IRQ_GPIO, GPIO_DIR_IN);
+#else /*PXA_310_LV */
+	/* receive input interrupts from the SMS 1000 on J32 pin 11 */
+	pxa_gpio_mode(22 | GPIO_IN);
+#endif /*PXA_310_LV */
+	speed = CLOCK_DIVIDER(CLOCK_FACTOR); /* clock divisor for this mode */
+	/* 32bit words in the fifo */
+	mode = SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS;
+	/* SSCR1 = flags */
+	flags = SSCR1_RxTresh(1) | SSCR1_TxTresh(1) | SSCR1_TSRE |
+	 SSCR1_RSRE | SSCR1_RIE | SSCR1_TRAIL;	/* | SSCR1_TIE */
+
+	ssp_config(&spiphy_dev->sspdev, mode, flags, psp_flags, speed);
+	ssp_disable(&(spiphy_dev->sspdev));
+#ifdef PXA_310_LV
+
+	pxa3xx_mfp_set_afds(MFP_PIN_GPIO95, MFP_AF1, MFP_DS03X);
+	pxa3xx_mfp_set_afds(MFP_PIN_GPIO96, MFP_AF1, MFP_DS03X);
+	pxa3xx_mfp_set_afds(MFP_PIN_GPIO97, MFP_AF1, MFP_DS03X);
+	pxa3xx_mfp_set_afds(MFP_PIN_GPIO98, MFP_AF1, MFP_DS03X);
+#else /*PXA_310_LV */
+	pxa_gpio_mode(GPIO23_SCLK_MD);
+	pxa_gpio_mode(GPIO24_SFRM_MD);
+	pxa_gpio_mode(GPIO25_STXD_MD);
+	pxa_gpio_mode(GPIO26_SRXD_MD);
+#endif /*PXA_310_LV */
+	/* setup the dma */
+	spiphy_dev->rx_dma_channel =
+	    pxa_request_dma("spibusdrv_rx", DMA_PRIO_HIGH, spibus_dma_handler,
+			    spiphy_dev);
+	if (spiphy_dev->rx_dma_channel < 0) {
+		ret = -EBUSY;
+		PERROR("Could not get RX DMA channel.\n");
+		goto error_rxdma;
+	}
+	spiphy_dev->tx_dma_channel =
+	    pxa_request_dma("spibusdrv_tx", DMA_PRIO_HIGH, spibus_dma_handler,
+			    spiphy_dev);
+	if (spiphy_dev->tx_dma_channel < 0) {
+		ret = -EBUSY;
+		PERROR("Could not get TX DMA channel.\n");
+		goto error_txdma;
+	}
+
+	SDCMR_RX = DRCMR_MAPVLD | spiphy_dev->rx_dma_channel;
+	SDCMR_TX = DRCMR_MAPVLD | spiphy_dev->tx_dma_channel;
+
+	PDEBUG("dma rx channel: %d, dma tx channel: %d\n",
+	       spiphy_dev->rx_dma_channel, spiphy_dev->tx_dma_channel);
+	/* enable the clock */
+
+	spiphy_dev->interruptHandler = smsspi_interruptHandler;
+	spiphy_dev->intr_context = intr_context;
+#ifdef PXA_310_LV
+	set_irq_type(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), IRQT_FALLING);
+	ret =
+	    request_irq(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), spibus_interrupt,
+			SA_INTERRUPT, "SMSSPI", spiphy_dev);
+#else /*PXA_310_LV */
+	set_irq_type(IRQ_GPIO(22), IRQT_FALLING);
+	ret =
+	    request_irq(IRQ_GPIO(22), spibus_interrupt, SA_INTERRUPT, "SMSSPI",
+			&(g_spidata.sspdev));
+#endif /*PXA_310_LV */
+	if (ret) {
+		PERROR("Could not get interrupt for SMS device. status =%d\n",
+		       ret);
+		goto error_irq;
+	}
+
+	ssp_enable(&(spiphy_dev->sspdev));
+	PDEBUG("exiting\n");
+	return spiphy_dev;
+error_irq:
+	if (spiphy_dev->tx_dma_channel >= 0)
+		pxa_free_dma(spiphy_dev->tx_dma_channel);
+
+error_txdma:
+	if (spiphy_dev->rx_dma_channel >= 0)
+		pxa_free_dma(spiphy_dev->rx_dma_channel);
+
+error_rxdma:
+	ssp_exit(&spiphy_dev->sspdev);
+error_sspinit:
+	PDEBUG("exiting on error\n");
+	return 0;
+}
+
+int smsspiphy_deinit(void *context)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	PDEBUG("entering\n");
+
+	/* disable the spi port */
+	ssp_flush(&spiphy_dev->sspdev);
+	ssp_disable(&spiphy_dev->sspdev);
+
+	/*  release DMA resources */
+	if (spiphy_dev->rx_dma_channel >= 0)
+		pxa_free_dma(spiphy_dev->rx_dma_channel);
+
+	if (spiphy_dev->tx_dma_channel >= 0)
+		pxa_free_dma(spiphy_dev->tx_dma_channel);
+
+	/* release Memory resources */
+#ifdef PXA_310_LV
+	free_irq(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), spiphy_dev);
+#else /*PXA_310_LV */
+	free_irq(IRQ_GPIO(22), &spiphy_dev->sspdev);
+#endif /*PXA_310_LV */
+	ssp_exit(&spiphy_dev->sspdev);
+	PDEBUG("exiting\n");
+	return 0;
+}
+
+void smsspiphy_set_config(spiphy_dev_st *spiphy_dev, int clock_divider)
+{
+	u32 mode, flags, speed, psp_flags = 0;
+	ssp_disable(&spiphy_dev->sspdev);
+	/* clock divisor for this mode. */
+	speed = CLOCK_DIVIDER(clock_divider);
+	/* 32bit words in the fifo */
+	mode = SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS;
+	flags = SSCR1_RxTresh(1) | SSCR1_TxTresh(1) | SSCR1_TSRE | SSCR1_RSRE | SSCR1_RIE | SSCR1_TRAIL;	/* | SSCR1_TIE */
+	ssp_config(&spiphy_dev->sspdev, mode, flags, psp_flags, speed);
+	ssp_enable(&spiphy_dev->sspdev);
+}
+
+void prepareForFWDnl(void *context)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	smsspiphy_set_config(spiphy_dev, 2);
+	msleep(100);
+}
+
+void fwDnlComplete(void *context, int App)
+{
+	spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+	smsspiphy_set_config(spiphy_dev, 1);
+	msleep(100);
+}

[-- Attachment #3: Type: text/plain, Size: 150 bytes --]

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [linux-dvb] [PATCH 2/5] SPI interface driver for Siano's SMS chip-set based devices.
  2008-11-19  9:03 [linux-dvb] [PATCH 2/5] SPI interface driver for Siano's SMS chip-set based devices Uri Shkolnik
@ 2008-11-19 10:24 ` Christophe Thommeret
  2008-11-19 11:53   ` Uri Shkolnik
  0 siblings, 1 reply; 10+ messages in thread
From: Christophe Thommeret @ 2008-11-19 10:24 UTC (permalink / raw)
  To: linux-dvb

Le mercredi 19 novembre 2008 10:03:04 Uri Shkolnik, vous avez écrit :
> This patch provides SPI interface driver for SMS chip-set based devices.
> The patch includes common SMS SPI code, and adapter driver for PXA310
>
>
> Signed-off-by: Uri Shkolnik <uris@siano-ms.com>

Hi Uri,

This patch also adds backup files ( e.g. smsspicommon.c~ ) !
Maybe others do also, haven't checked.

So, i guess it will be rejected :)

-- 
Christophe Thommeret


_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [linux-dvb] [PATCH 2/5] SPI interface driver for Siano's SMS chip-set based devices.
  2008-11-19 10:24 ` Christophe Thommeret
@ 2008-11-19 11:53   ` Uri Shkolnik
  2008-11-19 12:40     ` [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support Uri Shkolnik
  0 siblings, 1 reply; 10+ messages in thread
From: Uri Shkolnik @ 2008-11-19 11:53 UTC (permalink / raw)
  To: linux-dvb, Christophe Thommeret

Please note that this specific patch should be ignored (the diff file contains temporary files)
I submit a new patch.

Sorry about this silly silly mistake

Uri


--- On Wed, 11/19/08, Christophe Thommeret <hftom@free.fr> wrote:

> From: Christophe Thommeret <hftom@free.fr>
> Subject: Re: [linux-dvb] [PATCH 2/5] SPI interface driver for Siano's SMS chip-set based devices.
> To: linux-dvb@linuxtv.org
> Cc: "Uri Shkolnik" <urishk@yahoo.com>
> Date: Wednesday, November 19, 2008, 12:24 PM
> Le mercredi 19 novembre 2008 10:03:04 Uri Shkolnik, vous
> avez écrit :
> > This patch provides SPI interface driver for SMS
> chip-set based devices.
> > The patch includes common SMS SPI code, and adapter
> driver for PXA310
> >
> >
> > Signed-off-by: Uri Shkolnik <uris@siano-ms.com>
> 
> Hi Uri,
> 
> This patch also adds backup files ( e.g. smsspicommon.c~ )
> !
> Maybe others do also, haven't checked.
> 
> So, i guess it will be rejected :)
> 
> -- 
> Christophe Thommeret


      

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
  2008-11-19 11:53   ` Uri Shkolnik
@ 2008-11-19 12:40     ` Uri Shkolnik
  2008-11-19 17:35       ` Andrea Venturi
  2008-12-05 19:08       ` BOUWSMA Barry
  0 siblings, 2 replies; 10+ messages in thread
From: Uri Shkolnik @ 2008-11-19 12:40 UTC (permalink / raw)
  To: linux-dvb

[-- Attachment #1: Type: text/plain, Size: 573 bytes --]

Siano DTV module works with three subsystem API (DVB-API v3, DVB-API v5 (S2) and SmsHost)

Until now, only the DVB-API v3 has been supported.
The following two patch's parts add the support for the two other APIs.

The first adds the SmsHost API support. This API supports DTV standards yet to be fully supported by the DVB-API (CMMB, T-DMB and more).

The second part adds support for the DVB-API v5 ("S2")

******

This patch adds Siano subsystem, which supports the CMMB, T-DMB, DVB-H and DAB-IPD TV standards.

Signed-off-by: Uri Shkolnik <uris@siano-ms.com>




      

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: smssys_patch.diff --]
[-- Type: text/x-diff; name="smssys_patch.diff", Size: 30569 bytes --]

This patch adds Siano subsystem, which supports the CMMB and T-DMB DTV standards.
The patch also adds Network interface (network drivers) in order to support the DVB-H and DAB-IP standards.

Signed-off-by: Uri Shkolnik <uris@siano-ms.com>


diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smschar.c v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smschar.c
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smschar.c	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smschar.c	2008-11-19 14:21:34.000000000 +0200
@@ -0,0 +1,652 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>	/* printk() */
+#include <linux/fs.h>		/* everything... */
+#include <linux/types.h>	/* size_t */
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <asm/system.h>		/* cli(), *_flags */
+#include <linux/uaccess.h>	/* copy_*_user */
+
+#include "smscoreapi.h"
+
+#include "smscharioctl.h"
+
+/* max number of packets allowed to be pending on queue*/
+#define SMS_CHR_MAX_Q_LEN	15
+#define SMSCHAR_NR_DEVS		7
+
+struct smschar_device_t {
+	struct cdev cdev;	/*!< Char device structure */
+	wait_queue_head_t waitq;	/* Processes waiting */
+	int cancel_waitq;
+	spinlock_t lock;	/*!< critical section */
+	int pending_count;
+	struct list_head pending_data;	/*!< list of pending data */
+	struct smscore_buffer_t *currentcb;
+	int device_index;
+	struct smscore_device_t *coredev;
+	struct smscore_client_t *smsclient;
+};
+
+/*!  Holds the major number of the device node. may be changed at load
+time.*/
+int smschar_major = 251;
+
+/*!  Holds the first minor number of the device node.
+may be changed at load time.*/
+int smschar_minor;  /*= 0*/
+
+/* macros that allow the load time parameters change*/
+module_param(smschar_major, int, S_IRUGO);
+module_param(smschar_minor, int, S_IRUGO);
+
+struct smschar_device_t smschar_devices[SMSCHAR_NR_DEVS];
+static int g_smschar_inuse;
+
+static int g_pnp_status_changed = 1;
+wait_queue_head_t g_pnp_event;
+
+/**
+ * unregisters sms client and returns all queued buffers
+ *
+ * @param dev pointer to the client context (smschar parameters block)
+ *
+ */
+static void smschar_unregister_client(struct smschar_device_t *dev)
+{
+	unsigned long flags;
+
+	if (dev->coredev && dev->smsclient) {
+		dev->cancel_waitq = 1;
+		wake_up_interruptible(&dev->waitq);
+
+		spin_lock_irqsave(&dev->lock, flags);
+
+		while (!list_empty(&dev->pending_data)) {
+			struct smscore_buffer_t *cb =
+			    (struct smscore_buffer_t *)dev->pending_data.next;
+			list_del(&cb->entry);
+
+			smscore_putbuffer(dev->coredev, cb);
+			dev->pending_count--;
+		}
+
+		if (dev->currentcb) {
+			smscore_putbuffer(dev->coredev, dev->currentcb);
+			dev->currentcb = NULL;
+			dev->pending_count--;
+		}
+
+		smscore_unregister_client(dev->smsclient);
+		dev->smsclient = NULL;
+
+		spin_unlock_irqrestore(&dev->lock, flags);
+	}
+}
+
+/**
+ * queues incoming buffers into buffers queue
+ *
+ * @param context pointer to the client context (smschar parameters block)
+ * @param cb pointer to incoming buffer descriptor
+ *
+ * @return 0 on success, <0 on queue overflow.
+ */
+static int smschar_onresponse(void *context, struct smscore_buffer_t *cb)
+{
+	struct smschar_device_t *dev = context;
+	unsigned long flags;
+
+	if (!dev) {
+		sms_err("recieved bad dev pointer\n");
+		return -EFAULT;
+	}
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (dev->pending_count > SMS_CHR_MAX_Q_LEN) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return -EBUSY;
+	}
+
+	dev->pending_count++;
+	/* if data channel, remove header */
+	if (dev->device_index) {
+		cb->size -= sizeof(struct SmsMsgHdr_ST);
+		cb->offset += sizeof(struct SmsMsgHdr_ST);
+	}
+
+	list_add_tail(&cb->entry, &dev->pending_data);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (waitqueue_active(&dev->waitq))
+		wake_up_interruptible(&dev->waitq);
+
+	return 0;
+}
+
+/**
+ * handles device removal event
+ *
+ * @param context pointer to the client context (smschar parameters block)
+ *
+ */
+static void smschar_onremove(void *context)
+{
+	struct smschar_device_t *dev = (struct smschar_device_t *)context;
+
+	smschar_unregister_client(dev);
+	dev->coredev = NULL;
+}
+
+/**
+ * registers client associated with the node
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smschar_open(struct inode *inode, struct file *file)
+{
+	struct smschar_device_t *dev = container_of(inode->i_cdev,
+						    struct smschar_device_t,
+						    cdev);
+	int rc = -ENODEV;
+
+	sms_info("entering index %d\n", dev->device_index);
+	if (dev->coredev) {
+		struct smsclient_params_t params;
+		params.initial_id = dev->device_index ?
+		    dev->device_index : SMS_HOST_LIB;
+		params.data_type = dev->device_index ? MSG_SMS_DAB_CHANNEL : 0;
+		params.onresponse_handler = smschar_onresponse;
+		params.onremove_handler = smschar_onremove;
+		params.context = dev;
+
+		rc = smscore_register_client(dev->coredev, &params,
+					     &dev->smsclient);
+		if (!rc)
+			file->private_data = dev;
+		dev->cancel_waitq = 0;
+		g_pnp_status_changed = 1;
+	}
+
+	if (rc)
+		sms_err(" exiting, rc %d\n", rc);
+
+	return rc;
+}
+
+/**
+ * unregisters client associated with the node
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ */
+static int smschar_release(struct inode *inode, struct file *file)
+{
+	smschar_unregister_client(file->private_data);
+
+	sms_info("exiting\n");
+
+	return 0;
+}
+
+/**
+ * copies data from buffers in incoming queue into a user buffer
+ *
+ * @param file File structure.
+ * @param buf Source buffer.
+ * @param count Size of source buffer.
+ * @param f_pos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t smschar_read(struct file *file, char __user *buf,
+			    size_t count, loff_t *f_pos)
+{
+	struct smschar_device_t *dev = file->private_data;
+	unsigned long flags;
+	int rc, copied = 0;
+
+	if (!buf) {
+		sms_err("Bad pointer recieved from user.\n");
+		return -EFAULT;
+	}
+	if (!dev->coredev || !dev->smsclient) {
+		sms_err("no client\n");
+		return -ENODEV;
+	}
+	rc = wait_event_interruptible(dev->waitq,
+				      !list_empty(&dev->pending_data)
+				      || (dev->cancel_waitq));
+	if (rc < 0) {
+		sms_err("wait_event_interruptible error %d\n", rc);
+		return rc;
+	}
+	if (dev->cancel_waitq)
+		return 0;
+	if (!dev->smsclient) {
+		sms_err("no client\n");
+		return -ENODEV;
+	}
+	spin_lock_irqsave(&dev->lock, flags);
+
+	while (!list_empty(&dev->pending_data) && (copied < count)) {
+		struct smscore_buffer_t *cb =
+		    (struct smscore_buffer_t *)dev->pending_data.next;
+		int actual_size = min(((int)count - copied), cb->size);
+		if (copy_to_user(&buf[copied], &((char *)cb->p)[cb->offset],
+				 actual_size)) {
+			sms_err("copy_to_user failed\n");
+			spin_unlock_irqrestore(&dev->lock, flags);
+			return -EFAULT;
+		}
+		copied += actual_size;
+		cb->offset += actual_size;
+		cb->size -= actual_size;
+
+		if (!cb->size) {
+			list_del(&cb->entry);
+			smscore_putbuffer(dev->coredev, cb);
+			dev->pending_count--;
+		}
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return copied;
+}
+
+/**
+ * sends the buffer to the associated device
+ *
+ * @param file File structure.
+ * @param buf Source buffer.
+ * @param count Size of source buffer.
+ * @param f_pos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t smschar_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *f_pos)
+{
+	struct smschar_device_t *dev;
+	void *buffer;
+
+	if (file == NULL) {
+		sms_err("file is NULL\n");
+		return EINVAL;
+	}
+
+	if (file->private_data == NULL) {
+		sms_err("file->private_data is NULL\n");
+		return -EINVAL;
+	}
+
+	dev = file->private_data;
+	if (!dev->smsclient) {
+		sms_err("no client\n");
+		return -ENODEV;
+	}
+
+	buffer = kmalloc(ALIGN(count, SMS_ALLOC_ALIGNMENT) + SMS_DMA_ALIGNMENT,
+			 GFP_KERNEL | GFP_DMA);
+	if (buffer) {
+		void *msg_buffer = (void *)SMS_ALIGN_ADDRESS(buffer);
+
+		if (!copy_from_user(msg_buffer, buf, count))
+			smsclient_sendrequest(dev->smsclient,
+					      msg_buffer, count);
+		else
+			count = 0;
+
+		kfree(buffer);
+	}
+
+	return count;
+}
+
+static int smschar_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct smschar_device_t *dev = file->private_data;
+	return smscore_map_common_buffer(dev->coredev, vma);
+}
+
+/**
+ * waits until buffer inserted into a queue. when inserted buffer offset
+ * are reportedto the calling process. previously reported buffer is
+ * returned to smscore pool.
+ *
+ * @param dev pointer to smschar parameters block
+ * @param touser pointer to a structure that receives incoming buffer offsets
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smschar_wait_get_buffer(struct smschar_device_t *dev,
+				   struct smschar_buffer_t *touser)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (dev->currentcb) {
+		smscore_putbuffer(dev->coredev, dev->currentcb);
+		dev->currentcb = NULL;
+		dev->pending_count--;
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	rc = wait_event_interruptible(dev->waitq,
+				      !list_empty(&dev->pending_data)
+				      || (dev->cancel_waitq));
+	if (rc < 0) {
+		sms_err("wait_event_interruptible error, rc=%d\n", rc);
+		return rc;
+	}
+	if (dev->cancel_waitq) {
+		touser->offset = 0;
+		touser->size = 0;
+		return 0;
+	}
+	if (!dev->smsclient) {
+		sms_err("no client\n");
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (!list_empty(&dev->pending_data)) {
+		struct smscore_buffer_t *cb =
+		    (struct smscore_buffer_t *)dev->pending_data.next;
+		touser->offset = cb->offset_in_common + cb->offset;
+		touser->size = cb->size;
+
+		list_del(&cb->entry);
+
+		dev->currentcb = cb;
+	} else {
+		touser->offset = 0;
+		touser->size = 0;
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+/**
+ * poll for data availability
+ *
+ * @param file File structure.
+ * @param wait kernel polling table.
+ *
+ * @return POLLIN flag if read data is available.
+ */
+static unsigned int smschar_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct smschar_device_t *dev;
+	int mask = 0;
+
+	if (file == NULL) {
+		sms_err("file is NULL\n");
+		return EINVAL;
+	}
+
+	if (file->private_data == NULL) {
+		sms_err("file->private_data is NULL\n");
+		return -EINVAL;
+	}
+
+	dev = file->private_data;
+
+	if (list_empty(&dev->pending_data)) {
+		sms_info("No data is ready, waiting for data recieve.\n");
+		poll_wait(file, &dev->waitq, wait);
+	}
+
+	if (!list_empty(&dev->pending_data))
+		mask |= POLLIN | POLLRDNORM;
+	return mask;
+}
+
+static int smschar_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	struct smschar_device_t *dev = file->private_data;
+	void __user *up = (void __user *)arg;
+
+	if (!dev->coredev || !dev->smsclient) {
+		sms_err("no client\n");
+		return -ENODEV;
+	}
+
+	switch (cmd) {
+	case SMSCHAR_SET_DEVICE_MODE:
+		return smscore_set_device_mode(dev->coredev, (int)arg);
+
+	case SMSCHAR_GET_DEVICE_MODE:
+		{
+			if (put_user(smscore_get_device_mode(dev->coredev),
+				     (int *)up))
+				return -EFAULT;
+			break;
+		}
+	case SMSCHAR_IS_DEVICE_PNP_EVENT:
+		{
+			sms_info("Waiting for PnP event.\n");
+			wait_event_interruptible(g_pnp_event,
+						 !g_pnp_status_changed);
+			g_pnp_status_changed = 0;
+			sms_info("PnP Event %d.\n", g_smschar_inuse);
+			if (put_user(g_smschar_inuse, (int *)up))
+				return -EFAULT;
+			break;
+		}
+	case SMSCHAR_GET_BUFFER_SIZE:
+		{
+			if (put_user
+			    (smscore_get_common_buffer_size(dev->coredev),
+			     (int *)up))
+				return -EFAULT;
+
+			break;
+		}
+
+	case SMSCHAR_WAIT_GET_BUFFER:
+		{
+			struct smschar_buffer_t touser;
+			int rc;
+
+			rc = smschar_wait_get_buffer(dev, &touser);
+			if (rc < 0)
+				return rc;
+
+			if (copy_to_user(up, &touser,
+					 sizeof(struct smschar_buffer_t)))
+				return -EFAULT;
+
+			break;
+		}
+	case SMSCHAR_CANCEL_WAIT_BUFFER:
+		{
+			dev->cancel_waitq = 1;
+			wake_up_interruptible(&dev->waitq);
+			break;
+		}
+	case SMSCHAR_GET_FW_FILE_NAME:
+		{
+			if (!up)
+				return -EINVAL;
+			return smscore_get_fw_filename(dev->coredev,
+				       ((struct
+					 smschar_get_fw_filename_ioctl_t
+					 *)up)->mode,
+				       ((struct
+					 smschar_get_fw_filename_ioctl_t
+					 *)up)->filename);
+		}
+	case SMSCHAR_SEND_FW_FILE:
+		{
+			if (!up)
+				return -EINVAL;
+			return smscore_send_fw_file(dev->coredev,
+					((struct
+					smschar_send_fw_file_ioctl_t
+					*)up)->fw_buf,
+					((struct
+					smschar_send_fw_file_ioctl_t
+					*)up)->fw_size);
+		}
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return 0;
+}
+
+struct file_operations smschar_fops = {
+	.owner = THIS_MODULE,
+	.read = smschar_read,
+	.write = smschar_write,
+	.open = smschar_open,
+	.release = smschar_release,
+	.mmap = smschar_mmap,
+	.poll = smschar_poll,
+	.ioctl = smschar_ioctl,
+};
+
+static int smschar_setup_cdev(struct smschar_device_t *dev, int index)
+{
+	int rc, devno = MKDEV(smschar_major, smschar_minor + index);
+
+	cdev_init(&dev->cdev, &smschar_fops);
+
+	dev->cdev.owner = THIS_MODULE;
+	dev->cdev.ops = &smschar_fops;
+
+	kobject_set_name(&dev->cdev.kobj, "Siano_sms%d", index);
+	rc = cdev_add(&dev->cdev, devno, 1);
+	sms_info("exiting %p %d, rc %d", dev, index, rc);
+
+	return rc;
+}
+
+/**
+ * smschar callback that called when device plugged in/out. the function
+ * register or unregisters char device interface according to plug in/out
+ *
+ * @param coredev pointer to device that is being plugged in/out
+ * @param device pointer to system device object
+ * @param arrival 1 on plug-on, 0 othewise
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smschar_hotplug(struct smscore_device_t *coredev,
+			   struct device *device, int arrival)
+{
+	int rc = 0, i;
+
+	sms_info("entering %d\n", arrival);
+
+	g_pnp_status_changed = 1;
+	if (arrival) {
+		/* currently only 1 instance supported */
+		if (!g_smschar_inuse) {
+			/* data notification callbacks assignment */
+			memset(smschar_devices, 0, SMSCHAR_NR_DEVS *
+			       sizeof(struct smschar_device_t));
+
+			/* Initialize each device. */
+			for (i = 0; i < SMSCHAR_NR_DEVS; i++) {
+				sms_info("create device %d", i);
+				smschar_setup_cdev(&smschar_devices[i], i);
+				INIT_LIST_HEAD(&smschar_devices[i].
+					       pending_data);
+				spin_lock_init(&smschar_devices[i].lock);
+				init_waitqueue_head(&smschar_devices[i].waitq);
+
+				smschar_devices[i].coredev = coredev;
+				smschar_devices[i].device_index = i;
+			}
+			g_smschar_inuse = 1;
+			wake_up_interruptible(&g_pnp_event);
+		}
+	} else {
+		/* currently only 1 instance supported */
+		if (g_smschar_inuse) {
+			/* Get rid of our char dev entries */
+			for (i = 0; i < SMSCHAR_NR_DEVS; i++) {
+				cdev_del(&smschar_devices[i].cdev);
+				sms_info("remove device %d\n", i);
+			}
+
+			g_smschar_inuse = 0;
+			wake_up_interruptible(&g_pnp_event);
+		}
+	}
+
+	sms_info("exiting, rc %d\n", rc);
+
+	return rc;		/* succeed */
+}
+
+int smschar_register(void)
+{
+	dev_t devno = MKDEV(smschar_major, smschar_minor);
+	int rc;
+
+	sms_info("registering device major=%d minor=%d\n", smschar_major,
+		 smschar_minor);
+	if (smschar_major) {
+		rc = register_chrdev_region(devno, SMSCHAR_NR_DEVS, "smschar");
+	} else {
+		rc = alloc_chrdev_region(&devno, smschar_minor,
+					 SMSCHAR_NR_DEVS, "smschar");
+		smschar_major = MAJOR(devno);
+	}
+
+	if (rc < 0) {
+		sms_warn("smschar: can't get major %d\n", smschar_major);
+		return rc;
+	}
+	init_waitqueue_head(&g_pnp_event);
+
+	return smscore_register_hotplug(smschar_hotplug);
+}
+
+void smschar_unregister(void)
+{
+	dev_t devno = MKDEV(smschar_major, smschar_minor);
+
+	unregister_chrdev_region(devno, SMSCHAR_NR_DEVS);
+	smscore_unregister_hotplug(smschar_hotplug);
+	sms_info("unregistered\n");
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smscharioctl.h v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smscharioctl.h
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smscharioctl.h	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smscharioctl.h	2008-11-19 14:21:34.000000000 +0200
@@ -0,0 +1,52 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#ifndef __SMS_CHAR_IOCTL_H__
+#define __SMS_CHAR_IOCTL_H__
+
+#include <linux/ioctl.h>
+
+struct smschar_buffer_t {
+	unsigned long offset;	/* offset in common buffer (mapped to user) */
+	int size;
+};
+
+struct smschar_get_fw_filename_ioctl_t {
+	int mode;
+	char filename[200];
+};
+
+struct smschar_send_fw_file_ioctl_t {
+	char *fw_buf;
+	int fw_size;
+};
+
+#define SMSCHAR_SET_DEVICE_MODE		_IOW('K', 0, int)
+#define SMSCHAR_GET_DEVICE_MODE		_IOR('K', 1, int)
+#define SMSCHAR_GET_BUFFER_SIZE		_IOR('K', 2, int)
+#define SMSCHAR_WAIT_GET_BUFFER		_IOR('K', 3, struct smschar_buffer_t)
+#define SMSCHAR_IS_DEVICE_PNP_EVENT 	_IOR('K', 4, int)
+#define SMSCHAR_GET_FW_FILE_NAME	\
+	_IOWR('K', 5, struct smschar_get_fw_filename_ioctl_t)
+#define SMSCHAR_SEND_FW_FILE		\
+	_IOW('K', 6, struct smschar_send_fw_file_ioctl_t)
+#define SMSCHAR_CANCEL_WAIT_BUFFER	_IO('K', 7)
+
+#endif /* __SMS_CHAR_IOCTL_H__ */
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsnet.c v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsnet.c
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsnet.c	1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsnet.c	2008-11-19 14:21:32.000000000 +0200
@@ -0,0 +1,455 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>	/* struct device, and other headers */
+#include <linux/etherdevice.h>	/* eth_type_trans */
+#include <linux/ip.h>		/* struct iphdr */
+#include <linux/ipv6.h>		/* struct ipv6hdr */
+#include <linux/in.h>
+
+#include "smscoreapi.h"
+
+#define IPV4VERSION			0x40
+#define IPV6VERSION			0x60
+#define GETIPVERSION(_x_)	((_x_) & 0xf0)
+
+struct smsnet_client_t {
+	struct list_head entry;
+
+	struct smscore_device_t *coredev;
+	struct smscore_client_t *smsclient;
+
+	int packet_length, splitpacket_length;
+	int header_length, splitheader_length;
+	u8 splitpacket[ETH_DATA_LEN];
+};
+
+struct list_head g_smsnet_clients;
+struct mutex g_smsnet_clientslock;
+
+struct net_device *g_smsnet_device;
+struct net_device_stats g_smsnet_stats;
+
+int g_smsnet_inuse;
+
+void smsnet_send_packet(u8 *buffer, int length)
+{
+	u8 *eth;
+	struct sk_buff *skb = dev_alloc_skb(length + ETH_HLEN + NET_IP_ALIGN);
+
+	if (!skb) {
+		g_smsnet_stats.rx_dropped++;
+		return;
+	}
+
+	skb_reserve(skb, NET_IP_ALIGN);
+
+	eth = (u8 *) skb_put(skb, length + ETH_HLEN);
+	memcpy(eth + ETH_HLEN, buffer, length);
+
+	eth[6] = 0;
+	eth[7] = 1;
+	eth[8] = 1;
+	eth[9] = 3;
+	eth[10] = 4;
+	eth[11] = 5;
+
+	if (GETIPVERSION(*buffer) == IPV4VERSION) {
+		eth[0] = 1;
+		eth[1] = 0;
+		eth[2] = 0x5e;
+		eth[3] = buffer[17] & 0x7f;
+		eth[4] = buffer[18];
+		eth[5] = buffer[19];
+
+		eth[12] = 0x08;
+		eth[13] = 0x00;
+	} else {
+		/* ip6 mcast address */
+		eth[0] = 0x33;
+		eth[1] = 0x33;
+		eth[2] = buffer[36];
+		eth[3] = buffer[37];
+		eth[4] = buffer[38];
+		eth[5] = buffer[39];
+
+		eth[12] = 0x86;
+		eth[13] = 0xdd;
+	}
+
+	skb->dev = g_smsnet_device;
+	skb->protocol = eth_type_trans(skb, g_smsnet_device);
+	skb->ip_summed = CHECKSUM_COMPLETE;
+
+	g_smsnet_stats.rx_packets++;
+	g_smsnet_stats.rx_bytes += skb->len;
+
+	netif_rx(skb);
+}
+
+int check_header(struct smsnet_client_t *client, u8 *buffer)
+{
+	struct iphdr *ip4_hdr;
+	struct ipv6hdr *ip6_hdr;
+	struct udphdr *udp_hdr;
+	u16 csum;
+
+	/* check if packet header is valid and it is a UDP */
+	if (GETIPVERSION(*buffer) == IPV4VERSION) {
+		ip4_hdr = (struct iphdr *)buffer;
+		csum = ip4_hdr->check;
+
+		ip4_hdr->check = 0;
+
+		/* check header checksum for IPv4 packets */
+		if (ip4_hdr->protocol != IPPROTO_UDP || csum !=
+		    ip_fast_csum(buffer, ip4_hdr->ihl)) {
+			ip4_hdr->check = csum;
+			return 0;
+		}
+
+		ip4_hdr->check = csum;
+		client->packet_length = ntohs(ip4_hdr->tot_len);
+	} else {
+		ip6_hdr = (struct ipv6hdr *)buffer;
+		udp_hdr = (struct udphdr *)(ip6_hdr + 1);
+
+		if ((ip6_hdr->nexthdr != IPPROTO_UDP) ||
+		    (ip6_hdr->payload_len != udp_hdr->len))
+			return 0;
+
+		client->packet_length = ntohs(ip6_hdr->payload_len) +
+		    sizeof(struct ipv6hdr);
+	}
+
+	/* check for abnormal packet length */
+	if (client->packet_length > ETH_DATA_LEN)
+		return 0;
+
+	return 1;
+}
+
+int smsnet_onresponse(void *context, struct smscore_buffer_t *cb)
+{
+	struct smsnet_client_t *client = (struct smsnet_client_t *)context;
+	int length, rest;
+	u8 ip_ver, *buffer;
+
+	buffer = ((u8 *) cb->p) + cb->offset + sizeof(struct SmsMsgHdr_ST);
+	length = cb->size - sizeof(struct SmsMsgHdr_ST);
+
+	if (client->splitheader_length) {
+		/* how much data is missing ? */
+		rest = client->header_length - client->splitheader_length;
+
+		/* do we have enough in this buffer ? */
+		rest = min(rest, length);
+
+		memcpy(&client->splitpacket[client->splitheader_length],
+		       buffer, rest);
+
+		client->splitheader_length += rest;
+
+		if (client->splitheader_length != client->header_length)
+			goto exit;
+
+		if (check_header(client, client->splitpacket)) {
+			buffer += rest;
+			length -= rest;
+
+			client->splitpacket_length = client->header_length;
+		}
+
+		client->splitheader_length = 0;
+	}
+
+	if (client->splitpacket_length) {
+		/* how much data is missing ? */
+		rest = client->packet_length - client->splitpacket_length;
+
+		/* do we have enough in this buffer ? */
+		rest = min(rest, length);
+
+		memcpy(&client->splitpacket[client->splitpacket_length],
+		       buffer, rest);
+
+		client->splitpacket_length += rest;
+
+		if (client->splitpacket_length != client->packet_length)
+			goto exit;
+
+		client->splitpacket_length = 0;
+
+		smsnet_send_packet(client->splitpacket, client->packet_length);
+
+		buffer += rest;
+		length -= rest;
+	}
+
+	while (length > 0) {
+		ip_ver = GETIPVERSION(*buffer);
+		while (length && (ip_ver != IPV4VERSION) &&
+		       (ip_ver != IPV6VERSION)) {
+			buffer++;
+			length--;
+			ip_ver = GETIPVERSION(*buffer);
+		}
+
+		/* No more data in section */
+		if (!length)
+			break;
+
+		/* Set the header length at start of packet according
+		   to the version no problem with the IP header cast, since
+		   we have at least 1 byte (we use only the first byte) */
+		client->header_length =
+		    (ip_ver == IPV4VERSION) ?
+		    (((struct iphdr *)buffer)->ihl * 4) :
+		    (sizeof(struct ipv6hdr) + sizeof(struct udphdr));
+
+		/*Check that Header length is at least 20 (min IPv4 length) */
+		if (client->header_length < 20) {
+			length--;
+			buffer++;
+			continue;
+		}
+
+		/* check split header case */
+		if (client->header_length > length) {
+			memcpy(client->splitpacket, buffer, length);
+			client->splitheader_length = length;
+			break;
+		}
+
+		if (check_header(client, buffer)) {
+			/* check split packet case */
+			if (client->packet_length > length) {
+				memcpy(client->splitpacket, buffer, length);
+				client->splitpacket_length = length;
+				break;
+			}
+		} else {
+			length--;
+			buffer++;
+			continue;
+		}
+
+		smsnet_send_packet(buffer, client->packet_length);
+
+		buffer += client->packet_length;
+		length -= client->packet_length;
+	}
+
+exit:
+	smscore_putbuffer(client->coredev, cb);
+
+	return 0;
+}
+
+void smsnet_unregister_client(struct smsnet_client_t *client)
+{
+	/* must be called under clientslock */
+
+	list_del(&client->entry);
+
+	smscore_unregister_client(client->smsclient);
+	kfree(client);
+}
+
+void smsnet_onremove(void *context)
+{
+	kmutex_lock(&g_smsnet_clientslock);
+
+	smsnet_unregister_client((struct smsnet_client_t *)context);
+
+	kmutex_unlock(&g_smsnet_clientslock);
+}
+
+int smsnet_hotplug(struct smscore_device_t *coredev, struct device *device,
+		   int arrival)
+{
+	struct smsclient_params_t params;
+	struct smsnet_client_t *client;
+	int rc;
+
+	/* device removal handled by onremove callback */
+	if (!arrival)
+		return 0;
+
+	client = kzalloc(sizeof(struct smsnet_client_t), GFP_KERNEL);
+	if (!client) {
+		printk(KERN_INFO "%s kmalloc() failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	params.initial_id = 1;
+	params.data_type = MSG_SMS_DATA_MSG;
+	params.onresponse_handler = smsnet_onresponse;
+	params.onremove_handler = smsnet_onremove;
+	params.context = client;
+
+	rc = smscore_register_client(coredev, &params, &client->smsclient);
+	if (rc < 0) {
+		printk(KERN_INFO "%s smscore_register_client() failed %d\n",
+		       __func__, rc);
+		kfree(client);
+		return rc;
+	}
+
+	client->coredev = coredev;
+
+	kmutex_lock(&g_smsnet_clientslock);
+
+	list_add(&client->entry, &g_smsnet_clients);
+
+	kmutex_unlock(&g_smsnet_clientslock);
+
+	printk(KERN_INFO "%s success\n", __func__);
+
+	return 0;
+}
+
+static int smsnet_open(struct net_device *dev)
+{
+	g_smsnet_inuse++;
+
+	netif_start_queue(dev);
+
+	printk(KERN_INFO "%s, %d\n", __func__, g_smsnet_inuse);
+
+	return 0;
+}
+
+static int smsnet_stop(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+
+	g_smsnet_inuse--;
+
+	printk(KERN_INFO "%s, %d\n", __func__, g_smsnet_inuse);
+
+	return 0;
+}
+
+static int smsnet_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	printk(KERN_INFO "%s\n", __func__);
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+static struct net_device_stats *smsnet_get_stats(struct net_device *dev)
+{
+	return &g_smsnet_stats;
+}
+
+static void smsnet_set_multicast_list(struct net_device *dev)
+{
+	printk(KERN_INFO "%s %d\n", __func__, dev->mc_count);
+	if (dev->mc_count) {
+		struct dev_mc_list *p;
+
+		for (p = dev->mc_list; p; p = p->next)
+			printk(KERN_INFO
+			"%s %d %02x %02x %02x %02x %02x %02x %02x %02x\n",
+			__func__, p->dmi_addrlen, p->dmi_addr[0],
+			p->dmi_addr[1], p->dmi_addr[2],
+			p->dmi_addr[3], p->dmi_addr[4],
+			p->dmi_addr[5], p->dmi_addr[6], p->dmi_addr[7]
+			);
+	}
+}
+
+static void smsnet_setup_device(struct net_device *dev)
+{
+	ether_setup(dev);
+
+	dev->open = smsnet_open;
+	dev->stop = smsnet_stop;
+	dev->hard_start_xmit = smsnet_hard_start_xmit;
+	dev->get_stats = smsnet_get_stats;
+	dev->set_multicast_list = smsnet_set_multicast_list;
+
+	dev->mc_count = 0;
+
+	memcpy(dev->dev_addr, "\0SIANO", ETH_ALEN);
+
+	dev->flags |= IFF_NOARP | IFF_MULTICAST | IFF_UP;
+	dev->features |= NETIF_F_IP_CSUM;
+}
+
+int smsnet_register(void)
+{
+	int rc;
+
+	INIT_LIST_HEAD(&g_smsnet_clients);
+	kmutex_init(&g_smsnet_clientslock);
+
+	memset(&g_smsnet_stats, 0, sizeof(g_smsnet_stats));
+
+	g_smsnet_device = alloc_netdev(0, "sms", smsnet_setup_device);
+	if (!g_smsnet_device) {
+		printk(KERN_INFO "%s alloc_netdev() failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	rc = register_netdev(g_smsnet_device);
+	if (rc < 0) {
+		printk(KERN_INFO "%s register_netdev() failed %d\n",
+		       __func__, rc);
+		free_netdev(g_smsnet_device);
+		return rc;
+	}
+
+	rc = smscore_register_hotplug(smsnet_hotplug);
+
+	printk(KERN_INFO "%s, rc %d\n", __func__, rc);
+
+	return rc;
+}
+
+void smsnet_unregister(void)
+{
+	if (g_smsnet_device) {
+		unregister_netdev(g_smsnet_device);
+		free_netdev(g_smsnet_device);
+
+		g_smsnet_device = NULL;
+	}
+
+	smscore_unregister_hotplug(smsnet_hotplug);
+
+	kmutex_lock(&g_smsnet_clientslock);
+
+	while (!list_empty(&g_smsnet_clients))
+		smsnet_unregister_client((struct smsnet_client_t *)
+					 g_smsnet_clients.next);
+
+	kmutex_unlock(&g_smsnet_clientslock);
+
+	printk(KERN_INFO "%s\n", __func__);
+}
+
+MODULE_DESCRIPTION("Siano Network Client module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");

[-- Attachment #3: Type: text/plain, Size: 150 bytes --]

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
  2008-11-19 12:40     ` [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support Uri Shkolnik
@ 2008-11-19 17:35       ` Andrea Venturi
  2008-11-19 18:00         ` Uri Shkolnik
  2008-12-05 19:08       ` BOUWSMA Barry
  1 sibling, 1 reply; 10+ messages in thread
From: Andrea Venturi @ 2008-11-19 17:35 UTC (permalink / raw)
  Cc: linux-dvb

Uri Shkolnik wrote:
> Siano DTV module works with three subsystem API (DVB-API v3, DVB-API v5 (S2) and SmsHost)
>
> Until now, only the DVB-API v3 has been supported.
> The following two patch's parts add the support for the two other APIs.
>
> The first adds the SmsHost API support. This API supports DTV standards yet to be fully supported by the DVB-API (CMMB, T-DMB and more).
>   

hi, as i live in italy under one of the few trials of T-DMB network,  
i'm interested in the T-DMB support.
i happen to own a Cinergy Terratec Piranha based on a SMS 100x chipset 
and under another OS i can lock and see the T-DMB services. i'd like to 
do the same under linux.

is there some public spec about this SmsHost API to hack a simple 
application to dump the TS from a T-DMB network?
google doesn't return with much interesting..

thanx

andrea venturi


_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
  2008-11-19 17:35       ` Andrea Venturi
@ 2008-11-19 18:00         ` Uri Shkolnik
  2008-11-23 10:09           ` Andrea Venturi
  0 siblings, 1 reply; 10+ messages in thread
From: Uri Shkolnik @ 2008-11-19 18:00 UTC (permalink / raw)
  To: Andrea Venturi; +Cc: linux-dvb




--- On Wed, 11/19/08, Andrea Venturi <a.venturi@avalpa.com> wrote:

> From: Andrea Venturi <a.venturi@avalpa.com>
> Subject: Re: [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
> To: 
> Cc: linux-dvb@linuxtv.org
> Date: Wednesday, November 19, 2008, 7:35 PM
> Uri Shkolnik wrote:
> > Siano DTV module works with three subsystem API
> (DVB-API v3, DVB-API v5 (S2) and SmsHost)
> >
> > Until now, only the DVB-API v3 has been supported.
> > The following two patch's parts add the support
> for the two other APIs.
> >
> > The first adds the SmsHost API support. This API
> supports DTV standards yet to be fully supported by the
> DVB-API (CMMB, T-DMB and more).
> >   
> 
> hi, as i live in italy under one of the few trials of T-DMB
> network,  
> i'm interested in the T-DMB support.
> i happen to own a Cinergy Terratec Piranha based on a SMS
> 100x chipset 
> and under another OS i can lock and see the T-DMB services.
> i'd like to 
> do the same under linux.
> 
> is there some public spec about this SmsHost API to hack a
> simple 
> application to dump the TS from a T-DMB network?
> google doesn't return with much interesting..
> 
> thanx
> 
> andrea venturi
> 
> 
> _______________________________________________
> linux-dvb mailing list
> linux-dvb@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

Hi Andrea,

In order to use T-DMB you need FIB parser to start with. Do you have such parser? Later on you'll need service and components manager and some other stuff as well.

Maybe I can provide you with user-space C library (binary, not source code) that does that and many other T-DMB tasks, if you'll provide me with you system characteristics.


Regards,

Uri


      

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
  2008-11-19 18:00         ` Uri Shkolnik
@ 2008-11-23 10:09           ` Andrea Venturi
  0 siblings, 0 replies; 10+ messages in thread
From: Andrea Venturi @ 2008-11-23 10:09 UTC (permalink / raw)
  To: linux-dvb

Uri Shkolnik wrote:
> Hi Andrea,
>
> In order to use T-DMB you need FIB parser to start with. Do you have such parser? Later on you'll need service and components manager and some other stuff as well.
>   

hi, i didn't get that for T-DMB to be decoded you need to parse some
other data structure.. maybe it's because the TS mux is piggybacked on a
DAM mux scheme..

i suppose i need to download and read the relevant standards both for
DAB and DMB like TS 102 427 and TS 102 428

anyway with regard some stuff about FIC decoding, there's already some
source code to peruse and borrow, like this gnuradio software DAB receiver:

http://people.ee.ethz.ch/~andrmuel/files/gnuradio/dab-doc/thesis.pdf
http://people.ee.ethz.ch/~andrmuel/files/gnuradio/gr-dab.tgz

maybe it's a good starting point..

> Maybe I can provide you with user-space C library (binary, not source code) that does that and many other T-DMB tasks, if you'll provide me with you system characteristics.
>   

having a reference implementation, albeit binary, could be also another
interesting starting point. thank you for the offering..

we run this stuff on x86 32 bit debian distro.. if you are so kind to
provide some binary tools..

thank you again

andrea
>
> Regards,
>
> Uri
>
>
>       
>
>   



_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
  2008-11-19 12:40     ` [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support Uri Shkolnik
  2008-11-19 17:35       ` Andrea Venturi
@ 2008-12-05 19:08       ` BOUWSMA Barry
  2008-12-05 20:20         ` Uri Shkolnik
  1 sibling, 1 reply; 10+ messages in thread
From: BOUWSMA Barry @ 2008-12-05 19:08 UTC (permalink / raw)
  To: Uri Shkolnik; +Cc: linux-dvb

Hello Uri; sorry that I have waited so long to reply to this...

On Wed, 19 Nov 2008, Uri Shkolnik wrote:

> The first adds the SmsHost API support. This API supports DTV standards yet to be fully supported by the DVB-API (CMMB, T-DMB and more).

The patches have all applied cleanly, and built properly,
thank you.  (Or, at least, I had no problems.)

However, what I have is probably a complete-newbie question,
that I should be ashamed to ask, because I *should* know better.


Is there a particular Linux distribution for which the Siano 
source code is intended, and, exactly what should I expect to
see in /dev when I successfully load the module with my device?


I ask this because on my test system, /dev major number 251
appears to be used by `usbdev' -- I'm using ``udev'' on what
I think is a sort-of-recent Debian system; whether I've updated 
`udev' here I can't say without looking -- I know I updated
`udev' on an earlier Debian system if not the one I'm running now...


I see on the static /dev (before possible `udev') that I have
mounted from my earlier Debian, before I decided that trying
to keep up-to-date was best done by a fresh install -- that
/dev major 251 is unused there.

I've updated `udev' independent of the rest of the OS in
the past out of necessity, and while I have not been able
to kill off the part of my brane that haunts me with the
memory of glowing tubes/valves, I can no longer remember
any details of my `udev' hacking.

Of course, I can use module-load-parameters to specify a
different major number, but I don't see any anticipated
character devices getting created upon module load -- if
I need to physically disconnect and reconnect the device
for this, then my apologies, as I didn't get around to that.
Yet.


I am sure I'm either doing something stupid, or I've been
to lazy to fix `udev' for myself, but I'm asking this to
try to help me save a few hours re-learning everything I've
forgotten about devices...


Of course, if Sir Mkrufky@ already has a fix in the works
for this, then I'll just shut up for a short spell.


Thanks!
barry bouwsma

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
  2008-12-05 19:08       ` BOUWSMA Barry
@ 2008-12-05 20:20         ` Uri Shkolnik
  2008-12-06 11:49           ` BOUWSMA Barry
  0 siblings, 1 reply; 10+ messages in thread
From: Uri Shkolnik @ 2008-12-05 20:20 UTC (permalink / raw)
  Cc: linux-dvb



--- On Fri, 12/5/08, BOUWSMA Barry <freebeer.bouwsma@gmail.com> wrote:

> From: BOUWSMA Barry <freebeer.bouwsma@gmail.com>
> Subject: Re: [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
> To: "Uri Shkolnik" <urishk@yahoo.com>
> Cc: linux-dvb@linuxtv.org
> Date: Friday, December 5, 2008, 9:08 PM
> Hello Uri; sorry that I have waited so long to reply to
> this...
>
> On Wed, 19 Nov 2008, Uri Shkolnik wrote:
>
> > The first adds the SmsHost API support. This API
> supports DTV standards yet to be fully supported by the
> DVB-API (CMMB, T-DMB and more).
>
> The patches have all applied cleanly, and built properly,
> thank you.  (Or, at least, I had no problems.)
>

Cool. 10x.

> However, what I have is probably a complete-newbie
> question,
> that I should be ashamed to ask, because I *should* know
> better.
>
>
> Is there a particular Linux distribution for which the
> Siano
> source code is intended, and, exactly what should I expect
> to
> see in /dev when I successfully load the module with my
> device?
>

Siano currently has dozens++ of customers using various flavors of Linux. Desktop systems (multiple distributions), embedded Linux (many types and targets) and some Linux derivative systems.

Some use Linux DVB v3 API, most don't (either their system are too small, and the kernel and user space are tailored to the specific target/product, or the DTV standards is unsupported by the DVB sub-system (CMMB, T-DMB and more)).

The Siano (mini/tini) sub-system comes to answer that need.

But....

In order to use the Siano sub-system you need to have C library in user space, and a compatible player (with most DTV standards, just DVB-H can be used with any RTP enabled multimedia player with the proper CODECs).

This C library is supplied usually only to commercial customer because that in many cases it evolve to a direct support given by Siano, simply because there is no other support resource... (as always, every rule has its own exceptions). Andrea Venturi asked this library about 10 days ago, and this request went up to Siano's VP of marketing....(still pending)

Siano is committed to support the LinuxTV community. But to support individual end-users its quite an overstretch... 

Anyway, dev node 251 is defined as "experimental/test" node, and is used by Siano for communication between the kernel's sub-system and the user space library and multimedia player (e.g. both control and data paths).


>
> I ask this because on my test system, /dev major number 251
> appears to be used by `usbdev' -- I'm using
> ``udev'' on what
> I think is a sort-of-recent Debian system; whether I've
> updated
> `udev' here I can't say without looking -- I know I
> updated
> `udev' on an earlier Debian system if not the one
> I'm running now...
>
>
> I see on the static /dev (before possible `udev') that
> I have
> mounted from my earlier Debian, before I decided that
> trying
> to keep up-to-date was best done by a fresh install -- that
> /dev major 251 is unused there.
>
> I've updated `udev' independent of the rest of the
> OS in
> the past out of necessity, and while I have not been able
> to kill off the part of my brane that haunts me with the
> memory of glowing tubes/valves, I can no longer remember
> any details of my `udev' hacking.
>
> Of course, I can use module-load-parameters to specify a
> different major number, but I don't see any anticipated
> character devices getting created upon module load -- if
> I need to physically disconnect and reconnect the device
> for this, then my apologies, as I didn't get around to
> that.
> Yet.
>
>
> I am sure I'm either doing something stupid, or
> I've been
> to lazy to fix `udev' for myself, but I'm asking
> this to
> try to help me save a few hours re-learning everything
> I've
> forgotten about devices...
>
>
> Of course, if Sir Mkrufky@ already has a fix in the works
> for this, then I'll just shut up for a short spell.
>

"Sir Mkrufky" ?
I like that... I'll ask Mike if I'm too have the privilege to refer him with that title....


>
> Thanks!
> barry bouwsma

Welcome...
Uri


      

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support
  2008-12-05 20:20         ` Uri Shkolnik
@ 2008-12-06 11:49           ` BOUWSMA Barry
  0 siblings, 0 replies; 10+ messages in thread
From: BOUWSMA Barry @ 2008-12-06 11:49 UTC (permalink / raw)
  To: Uri Shkolnik; +Cc: linux-dvb

On Fri, 5 Dec 2008, Uri Shkolnik wrote:

> > > The first adds the SmsHost API support. This API
> > supports DTV standards yet to be fully supported by the
> > DVB-API (CMMB, T-DMB and more).

> > Is there a particular Linux distribution for which the
> > Siano
> > source code is intended, and, exactly what should I expect
> > to
> > see in /dev when I successfully load the module with my
> > device?

> Siano currently has dozens++ of customers using various flavors 
> of Linux. Desktop systems (multiple distributions), embedded 
> Linux (many types and targets) and some Linux derivative 
> systems.

Okay, thanks.  Now I see that I should not need to rely on
features of a particular distribution...


> Some use Linux DVB v3 API, most don't (either their system are 
> too small, and the kernel and user space are tailored to the 
> specific target/product, or the DTV standards is unsupported by 
> the DVB sub-system (CMMB, T-DMB and more)).

You probably remember this, but just in case anyone else
is at all concerned, my interest for now is in DAB/DAB+
radio reception, for which the v3 API obviously is of no
help.

As far as I know, while the v5 API can include other norms
than DVB/ATSC, such as ISDB, it does not yet have support
for the DMB/DAB family -- and so, I will need to use the
SmsHost and character devices.  At least, until it is
decided whether and how to fit DAB into v5...

(I do not expect that the other part of your patch, which
will provide API v5 support, will resolve this, but I'll
nonetheless wait to see...)



> In order to use the Siano sub-system you need to have C library 
> in user space

Understood.  This is also the part which I am hoping to be
able to avoid, hacking my own userspace tools to accomplish
the minimum that I need to tune a particular DAB ensemble,
and pull the data out and somehow parse it into an mp2 stream.

Of course, I must do this step-by-step.  The easy part was to
apply the diffs; now the next step seems to be for me to get
the device nodes to appear, so that then I can ask about
tuning...


> Siano is committed to support the LinuxTV community. But to 
> support individual end-users its quite an overstretch...

I appreciate this, especially with the bad experience that I
and several other users and developers have just had with
other products.

And I'm hoping that the Linux community can also work to help
itself, so that you don't need to be bothered by individuals
such as myself, instead supporting competent individuals
such as The Honourable Mr Krufky and anyone else with whom you
have been in developmental contact.  So, I'll pass along to
other readers some of the things I've learned so far, in hopes
that others can benefit from them.


> Anyway, dev node 251 is defined as "experimental/test" node, and 
> is used by Siano for communication between the kernel's 
> sub-system and the user space library and multimedia player 
> (e.g. both control and data paths).

It appears that on my recent `udev'-afflicted system, this 
assigned range of experimental majors 240-254 is dynamically 
allocated from the top down on a first-come, first-served
basis.  Here's what I see in part when I `cat /proc/devices` ...

212 DVB
249 smschar
250 hidraw
251 usb_endpoint
252 usbmon
253 bsg
254 pcmcia

So, in my case, when loading the smsmdtv.ko module that I've
built, I have needed to override the default -- while on my
much older production system, nothing is seen above major 212.

By the way, if it's not obvious to anyone else wanting to
play with this, move any
/lib/modules/`uname -r`/kernel/drivers/media/dvb/siano/sms1xxx.ko
out of the way so that it doesn't get automagically loaded
while you're playing...


However, when reading the patch you provided, I see that I
can also specify this `smschar_major' module parameter as 0;
then a suitable value will be selected (however, apparently
it doesn't get revealed in the `dmesg' output, should I choose
this -- I'll try to offer a debug patch later).

Other useful module parameters are `debug' (debug=3 for me),
and default_mode -- the default being DVB-T BDA operation.

In my case, `default_mode=2' loads the firmware to support
DAB and by extension T-DMB.  Other values, seen in the
siano/smscoreapi.h file, would be =1 for DVB-H, or =3 for
T-DMB/DAB-IP -- how this differs from mode 2 I don't know,
and I don't know which is the better choice for me yet.
The default is =4; ISDB-T is likely to be =6 (BDA driver);
and CMMB is =7.  For those too lazy to look at the source.

There may be special attention needed to providing the
firmware in the right place -- it ``just works'' for me
so I've managed to get that right a long time ago.
That is, I see `dmesg' output like
smsusb1_detectmode: 2 "SMS TDMB Receiver"
and I am momentarily at peace with the world.


So I see that smschar_register() succeeds and the major
number is assigned appropriately.  Additionally,
smschar_setup_cdev() succeeds for the seven devices.
At the moment for me, I don't get anything appearing
anywhere in /dev with the proper major number, or for
that matter, in /sys/dev/char or anywhere else in sysfs
that I've seen.

I'm comparing the dvb-core source before I hack blindly,
but if I may ask another stupid question, would creating
the device at the appropriate major number also be handled
by the C library to which you have referred, or perhaps
by a user application to handle tuning?  And, also,
I suspect that as the source you posted allows me to
handle the case where dev major 251 is already in use,
as well as choosing a non-default minor, the userspace
library will also handle this.


It's obvious that I'm not a device driver author, and I
don't expect you to help with these simple questions that
are purely Linux-related -- I've a google and I know how
to use it!  It just takes time...




> "Sir Mkrufky" ? I like that... I'll ask Mike if I'm too have the 
> privilege to refer him with that title....

I have heard it said that sweets work well to attract,
well, something.  So I prefer to address people the way
I don't deserve to be treated.  If nothing else, it's
usually good to reduce the recipient to giggling helplessly.

On the other hand, I've experimented and set out a lump
of sugar, along with some rotten month-old cheese, some
apple vinegar, decaying liquefying vegetables, and the
like, and strangely, all the bugs and flies were not
drawn to the lump of sweetness.  Draw your own conclusion,
but, well, my dinner is waiting...


Anyway, Sir Shkolnik (I'm sorry, may I call you Sir?),
thank you for your help, and I'll go back to hacking on
the source to see what I can make appear...

barry bouwsma

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2008-12-06 11:48 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-19  9:03 [linux-dvb] [PATCH 2/5] SPI interface driver for Siano's SMS chip-set based devices Uri Shkolnik
2008-11-19 10:24 ` Christophe Thommeret
2008-11-19 11:53   ` Uri Shkolnik
2008-11-19 12:40     ` [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support Uri Shkolnik
2008-11-19 17:35       ` Andrea Venturi
2008-11-19 18:00         ` Uri Shkolnik
2008-11-23 10:09           ` Andrea Venturi
2008-12-05 19:08       ` BOUWSMA Barry
2008-12-05 20:20         ` Uri Shkolnik
2008-12-06 11:49           ` BOUWSMA Barry

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox