diff mbox

Siano 10226 Siano sub-system

Message ID 250460.60370.qm@web110812.mail.gq1.yahoo.com (mailing list archive)
State Superseded
Headers show

Commit Message

Uri Shkolnik Jan. 13, 2009, 1:22 p.m. UTC
# HG changeset patch
# User Uri Shkolnik <uris@siano-ms.com>
# Date 1231847968 -7200
# Node ID 0d667d493399447a285bac21f0f38162fbbc2241
# Parent  a9dd63fe39745548432a32617f059f2ed64b5d48
Siano sub-system

From: Uri Shkolnik <uris@siano-ms.com>

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

Priority: normal

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




      
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Trent Piepho Jan. 13, 2009, 10:54 p.m. UTC | #1
On Tue, 13 Jan 2009, Uri Shkolnik wrote:
>
> This patch adds Siano subsystem, which supports the CMMB and T-DMB DTV standards.
> The patch also adds Network interface (network driver) in order to support the DVB-H and DAB-IP standards.

Commit messages should be wrapped to 75 columns.
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uri Shkolnik Jan. 14, 2009, 5:24 a.m. UTC | #2
--- On Wed, 1/14/09, Trent Piepho <xyzzy@speakeasy.org> wrote:

> From: Trent Piepho <xyzzy@speakeasy.org>
> Subject: Re: [PATCH] Siano 10226 Siano sub-system
> To: "Uri Shkolnik" <urishk@yahoo.com>
> Cc: linux-media@vger.kernel.org
> Date: Wednesday, January 14, 2009, 12:54 AM
> On Tue, 13 Jan 2009, Uri Shkolnik wrote:
> >
> > This patch adds Siano subsystem, which supports the
> CMMB and T-DMB DTV standards.
> > The patch also adds Network interface (network driver)
> in order to support the DVB-H and DAB-IP standards.
> 
> Commit messages should be wrapped to 75 columns.

Thanks. Will be corrected ASAP.

Where can I find checklist for that? (coding style and checkpatch.pl are for the source code itself. Which document that covers this?)


      
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Trent Piepho Jan. 15, 2009, 5:44 p.m. UTC | #3
On Tue, 13 Jan 2009, Uri Shkolnik wrote:
> --- On Wed, 1/14/09, Trent Piepho <xyzzy@speakeasy.org> wrote:
> > From: Trent Piepho <xyzzy@speakeasy.org>
> > Subject: Re: [PATCH] Siano 10226 Siano sub-system
> > To: "Uri Shkolnik" <urishk@yahoo.com>
> > Cc: linux-media@vger.kernel.org
> > Date: Wednesday, January 14, 2009, 12:54 AM
> > On Tue, 13 Jan 2009, Uri Shkolnik wrote:
> > >
> > > This patch adds Siano subsystem, which supports the
> > CMMB and T-DMB DTV standards.
> > > The patch also adds Network interface (network driver)
> > in order to support the DVB-H and DAB-IP standards.
> >
> > Commit messages should be wrapped to 75 columns.
>
> Thanks. Will be corrected ASAP.
>
> Where can I find checklist for that? (coding style and checkpatch.pl are for the source code itself. Which document that covers this?)

In the commit message "make commit" you to fill in, it says 74 characters.

In README.patches the instructions are slightly different, it says 68
characters for the title and 80 characters for the body of the commit
message.  That should probably be updated.

I'm not sure where it says that commit messages in the kernel, or simply
for git in general, should be 75 columns.  If you use stgit, the initial
commit message tells you that.  I think most developers just notice that
since git indents each line of the commit message by 4 spaces when you look
at the commit with git log or git show, that they look like crap on an 80
column terminal if the lines aren't wrapped at 75 characters.
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uri Shkolnik Jan. 15, 2009, 6:45 p.m. UTC | #4
--- On Thu, 1/15/09, Trent Piepho <xyzzy@speakeasy.org> wrote:

> From: Trent Piepho <xyzzy@speakeasy.org>
> Subject: Re: [PATCH] Siano 10226 Siano sub-system
> To: "Uri Shkolnik" <urishk@yahoo.com>
> Cc: linux-media@vger.kernel.org
> Date: Thursday, January 15, 2009, 7:44 PM
> On Tue, 13 Jan 2009, Uri Shkolnik wrote:
> > --- On Wed, 1/14/09, Trent Piepho
> <xyzzy@speakeasy.org> wrote:
> > > From: Trent Piepho <xyzzy@speakeasy.org>
> > > Subject: Re: [PATCH] Siano 10226 Siano sub-system
> > > To: "Uri Shkolnik"
> <urishk@yahoo.com>
> > > Cc: linux-media@vger.kernel.org
> > > Date: Wednesday, January 14, 2009, 12:54 AM
> > > On Tue, 13 Jan 2009, Uri Shkolnik wrote:
> > > >
> > > > This patch adds Siano subsystem, which
> supports the
> > > CMMB and T-DMB DTV standards.
> > > > The patch also adds Network interface
> (network driver)
> > > in order to support the DVB-H and DAB-IP
> standards.
> > >
> > > Commit messages should be wrapped to 75 columns.
> >
> > Thanks. Will be corrected ASAP.
> >
> > Where can I find checklist for that? (coding style and
> checkpatch.pl are for the source code itself. Which document
> that covers this?)
> 
> In the commit message "make commit" you to fill
> in, it says 74 characters.
> 
> In README.patches the instructions are slightly different,
> it says 68
> characters for the title and 80 characters for the body of
> the commit
> message.  That should probably be updated.
> 
> I'm not sure where it says that commit messages in the
> kernel, or simply
> for git in general, should be 75 columns.  If you use
> stgit, the initial
> commit message tells you that.  I think most developers
> just notice that
> since git indents each line of the commit message by 4
> spaces when you look
> at the commit with git log or git show, that they look like
> crap on an 80
> column terminal if the lines aren't wrapped at 75
> characters.

I fully understand now. 
To be on the safe side (maybe too safe), I'll use the minimum (68), even if it might be wrong (7 characters won't effect it much anyway).

Thanks for the explanation. 

Uri


      
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
CityK Jan. 16, 2009, 1:49 a.m. UTC | #5
Uri Shkolnik wrote:
> Where can I find checklist for that? (coding style and checkpatch.pl are for the source code itself. Which document that covers this?)

In addition to the info Trent provided, if you haven't already found it,
there are a couple of documents in /usr/src/linux/Documentation that are
worthwhile skimming through. We have repeated them here in the wiki,
under the development section:
- http://www.linuxtv.org/wiki/index.php/Development:_Coding_Style
- http://www.linuxtv.org/wiki/index.php/Development:_Submitting_Patches
-
http://www.linuxtv.org/wiki/index.php/Development:_Linux_Kernel_patch_submittal_checklist
- http://www.linuxtv.org/wiki/index.php/Development:_Submitting_Drivers
As well as providing our own brief notice:
- http://www.linuxtv.org/wiki/index.php/Development:_How_to_submit_patches
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff -r a9dd63fe3974 -r 0d667d493399 linux/drivers/media/dvb/siano/smschar.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smschar.c	Tue Jan 13 13:59:28 2009 +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		17
+
+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 -r a9dd63fe3974 -r 0d667d493399 linux/drivers/media/dvb/siano/smscharioctl.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smscharioctl.h	Tue Jan 13 13:59:28 2009 +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 -r a9dd63fe3974 -r 0d667d493399 linux/drivers/media/dvb/siano/smsnet.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smsnet.c	Tue Jan 13 13:59:28 2009 +0200
@@ -0,0 +1,442 @@ 
+/****************************************************************
+
+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) {
+		sms_err("kmalloc() failed");
+		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) {
+		sms_err("smscore_register_client() failed %d", 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);
+	sms_info("success");
+	return 0;
+}
+
+static int smsnet_open(struct net_device *dev)
+{
+	g_smsnet_inuse++;
+
+	netif_start_queue(dev);
+	sms_info("smsnet in use %d", g_smsnet_inuse);
+	return 0;
+}
+
+static int smsnet_stop(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	g_smsnet_inuse--;
+	sms_info("smsnet in use %d", g_smsnet_inuse);
+	return 0;
+}
+
+static int smsnet_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	sms_info("enter");
+	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)
+{
+	sms_info("mc count %d", dev->mc_count);
+	if (dev->mc_count) {
+		struct dev_mc_list *p;
+
+		for (p = dev->mc_list; p; p = p->next)
+			sms_info(
+			"%d %02x %02x %02x %02x %02x %02x %02x %02x",
+			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) {
+		sms_err("alloc_netdev() failed");
+		return -ENOMEM;
+	}
+
+	rc = register_netdev(g_smsnet_device);
+	if (rc < 0) {
+		sms_err("register_netdev() failed %d\n", rc);
+		free_netdev(g_smsnet_device);
+		return rc;
+	}
+
+	rc = smscore_register_hotplug(smsnet_hotplug);
+	sms_info("exit - rc %d", 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);
+
+	sms_info("exit");
+}
+
+MODULE_DESCRIPTION("Siano Network Client module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");