add cmmb moudle file directory.
authorzyc <zyc@rock-chips.com>
Sat, 21 Aug 2010 06:47:45 +0000 (14:47 +0800)
committerzyc <zyc@rock-chips.com>
Sat, 21 Aug 2010 06:47:45 +0000 (14:47 +0800)
26 files changed:
drivers/cmmb/Kconfig [new file with mode: 0755]
drivers/cmmb/Makefile [new file with mode: 0755]
drivers/cmmb/cmmb_class.c [new file with mode: 0755]
drivers/cmmb/cmmb_class.h [new file with mode: 0755]
drivers/cmmb/cmmb_memory.c [new file with mode: 0755]
drivers/cmmb/cmmb_memory.h [new file with mode: 0755]
drivers/cmmb/cmmb_ringbuffer.c [new file with mode: 0755]
drivers/cmmb/cmmb_ringbuffer.h [new file with mode: 0755]
drivers/cmmb/siano/Kconfig [new file with mode: 0755]
drivers/cmmb/siano/Makefile [new file with mode: 0755]
drivers/cmmb/siano/compat.h [new file with mode: 0755]
drivers/cmmb/siano/sms-cards.c [new file with mode: 0755]
drivers/cmmb/siano/sms-cards.h [new file with mode: 0755]
drivers/cmmb/siano/smschar.c [new file with mode: 0755]
drivers/cmmb/siano/smscharioctl.h [new file with mode: 0755]
drivers/cmmb/siano/smscoreapi.c [new file with mode: 0755]
drivers/cmmb/siano/smscoreapi.h [new file with mode: 0755]
drivers/cmmb/siano/smsdbg_prn.h [new file with mode: 0755]
drivers/cmmb/siano/smsendian.c [new file with mode: 0755]
drivers/cmmb/siano/smsendian.h [new file with mode: 0755]
drivers/cmmb/siano/smsspicommon.c [new file with mode: 0755]
drivers/cmmb/siano/smsspicommon.h [new file with mode: 0755]
drivers/cmmb/siano/smsspilog.c [new file with mode: 0755]
drivers/cmmb/siano/smsspiphy.h [new file with mode: 0755]
drivers/cmmb/siano/smsspiphy_pxa.c [new file with mode: 0755]
drivers/cmmb/siano/smsspiphy_rk.c [new file with mode: 0755]

diff --git a/drivers/cmmb/Kconfig b/drivers/cmmb/Kconfig
new file mode 100755 (executable)
index 0000000..9df2cd2
--- /dev/null
@@ -0,0 +1,11 @@
+
+ menu "CMMB"
+ config CMMB
+-tristate "ROCKCHIP CMMB"
+ >---default y
+ >---help
+          rk28 cmmb module.
+ ----------
+ source "drivers/cmmb/siano/Kconfig"
+ endmenu
diff --git a/drivers/cmmb/Makefile b/drivers/cmmb/Makefile
new file mode 100755 (executable)
index 0000000..e32d384
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for the dsp core.
+#
+
+obj-$(CONFIG_CMMB)     += cmmb_ringbuffer.o
+obj-$(CONFIG_CMMB)     += cmmb_class.o
+obj-$(CONFIG_CMMB)     += cmmb_memory.o
+
+obj-$(CONFIG_CMMB) += siano/
diff --git a/drivers/cmmb/cmmb_class.c b/drivers/cmmb/cmmb_class.c
new file mode 100755 (executable)
index 0000000..2c7d99b
--- /dev/null
@@ -0,0 +1,231 @@
+#include <linux/types.h>\r
+#include <linux/errno.h>\r
+#include <linux/string.h>\r
+#include <linux/module.h>\r
+#include <linux/kernel.h>\r
+#include <linux/init.h>\r
+#include <linux/slab.h>\r
+#include <linux/device.h>\r
+#include <linux/fs.h>\r
+#include <linux/cdev.h>\r
+#include <linux/mutex.h>\r
+\r
+#include "cmmb_class.h"\r
+\r
+\r
+#if 1\r
+#define DBGERR(fmt...)    printk(KERN_DEBUG fmt)\r
+#else\r
+#define DBGERR(fmt...)\r
+#endif\r
+\r
+#if 0\r
+#define DBG(fmt...)    printk(KERN_DEBUG fmt)\r
+#else\r
+#define DBG(fmt...)\r
+#endif\r
+\r
+#define MAX_CMMB_ADAPTER    2\r
+#define MAX_CMMB_MINORS (MAX_CMMB_ADAPTER*4)\r
+\r
+\r
+struct cmmb_adapter CMMB_adapter;\r
+struct class * cmmb_class;\r
+\r
+static struct cdev cmmb_device_cdev;\r
+\r
+static int cmmb_device_open(struct inode *inode, struct file *file);\r
+\r
+static struct file_operations cmmb_device_fops =\r
+{\r
+       .owner =        THIS_MODULE,\r
+       .open =         cmmb_device_open\r
+};\r
+\r
+static struct cmmb_device* cmmb_find_device (int minor)\r
+{\r
+       \r
+    struct cmmb_device *dev;\r
+    DBG("[CMMB HW]:[class]:enter cmmb_find_device\n");\r
+               \r
+       list_for_each_entry(dev, &CMMB_adapter.device_list, list_head)\r
+       if (dev->type == minor)\r
+       return dev;\r
+       \r
+       return NULL;\r
+}\r
+\r
+static int cmmb_device_open(struct inode *inode, struct file *file)\r
+{\r
+       struct cmmb_device *cmmbdev;\r
+    \r
+    DBG("[CMMB HW]:[class]:enter cmmb_device_open\n");\r
+    \r
+       cmmbdev = cmmb_find_device (iminor(inode));\r
+    \r
+    DBG("[CMMB HW]:[class]:cmmbdev.type%d\n",cmmbdev->type);\r
+    \r
+       if (cmmbdev && cmmbdev->fops) {\r
+               int err = 0;\r
+               const struct file_operations *old_fops;\r
+\r
+               file->private_data = cmmbdev;\r
+               old_fops = file->f_op;\r
+               file->f_op = fops_get(cmmbdev->fops);\r
+               if(file->f_op->open)\r
+                       err = file->f_op->open(inode,file);\r
+               if (err) {\r
+                       fops_put(file->f_op);\r
+                       file->f_op = fops_get(old_fops);\r
+               }\r
+               fops_put(old_fops);\r
+               return err;\r
+       }\r
+       return -ENODEV;\r
+}\r
+\r
+\r
+static int cmmb_register_adapter(const char *name, struct device *device)\r
+{\r
+    DBG("[CMMB HW]:[class]:cmmb_register_adapter\n");\r
+\r
+       memset (&CMMB_adapter, 0, sizeof(struct cmmb_adapter));\r
+    \r
+       INIT_LIST_HEAD (&CMMB_adapter.device_list);\r
+\r
+       CMMB_adapter.num = 0;\r
+       CMMB_adapter.name = name;\r
+       CMMB_adapter.device = device;\r
+    \r
+       return 0;\r
+}\r
+\r
+\r
+static int cmmb_unregister_adapter(struct cmmb_adapter *adap)\r
+{\r
+    DBG("[CMMB HW]:[class]:cmmb_unregister_adapter\n");\r
+    \r
+       memset (&CMMB_adapter, 0, sizeof(struct cmmb_adapter));\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+int cmmb_register_device(struct cmmb_adapter *adap, struct cmmb_device **pcmmbdev,\r
+                        struct file_operations *fops, void *priv, int type,char* name)\r
+{\r
+       struct cmmb_device *cmmbdev;\r
+       struct file_operations *cmmbdevfops;\r
+       struct device *clsdev;\r
+\r
+    DBG("[CMMB HW]:[class]:cmmb_register_device\n");\r
+    \r
+       *pcmmbdev = cmmbdev = kmalloc(sizeof(struct cmmb_device), GFP_KERNEL);\r
+    if(!pcmmbdev)\r
+    {\r
+       DBGERR("[CMMB HW]:[class]:[err]: cmmb register device cmmbdev malloc fail!!!\n");\r
+       return -ENOMEM;\r
+    }\r
+    \r
+       cmmbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);\r
+\r
+       if (!cmmbdevfops){\r
+        DBGERR("[CMMB HW]:[class]:[err]: cmmb register device cmmbdevfops malloc fail!!!\n");\r
+               kfree (cmmbdev);\r
+               return -ENOMEM;\r
+       }\r
+\r
+       cmmbdev->type = type;\r
+       cmmbdev->adapter = adap;\r
+       cmmbdev->priv = priv;\r
+       cmmbdev->fops = cmmbdevfops;\r
+    \r
+       init_waitqueue_head (&cmmbdev->wait_queue);\r
+\r
+       memcpy(cmmbdev->fops, fops, sizeof(struct file_operations));\r
+       cmmbdev->fops->owner = THIS_MODULE;\r
+\r
+       list_add_tail (&cmmbdev->list_head, &adap->device_list);\r
+\r
+       clsdev = device_create(cmmb_class, adap->device,MKDEV(CMMB_MAJOR, type),NULL,name);\r
+       if (IS_ERR(clsdev)) {\r
+               DBGERR("[CMMB HW]:[class]:[err]: creat dev fail!!!\n");\r
+               return PTR_ERR(clsdev);\r
+       }\r
+    \r
+       return 0;\r
+}\r
+EXPORT_SYMBOL(cmmb_register_device);\r
+\r
+\r
+void cmmb_unregister_device(struct cmmb_device *cmmbdev)\r
+{\r
+       if (!cmmbdev)\r
+               return;\r
+    \r
+    DBG("[CMMB HW]:[class]:cmmb_unregister_device\n");\r
+\r
+       device_destroy(cmmb_class, MKDEV(CMMB_MAJOR, cmmbdev->type));\r
+\r
+       list_del (&cmmbdev->list_head);\r
+       kfree (cmmbdev->fops);\r
+       kfree (cmmbdev);\r
+}\r
+EXPORT_SYMBOL(cmmb_unregister_device);\r
+\r
+static int __init init_cmmbclass(void)\r
+{\r
+    int retval;\r
+    struct cmmb_adapter* cmmbadapter;\r
+    struct cmmb_device * tunerdev;\r
+    dev_t dev = MKDEV(CMMB_MAJOR, 0);\r
+    \r
+    DBG("[CMMB HW]:[class]: init_cmmbclass\n");\r
+\r
+       if ((retval = register_chrdev_region(dev, CMMB_MAJOR, "CMMB")) != 0){\r
+               DBGERR("[CMMB HW]:[class]:[err]: register chrdev fail!!!\n");\r
+               return retval;\r
+       }\r
+\r
+       cdev_init(&cmmb_device_cdev, &cmmb_device_fops);\r
+       if ((retval = cdev_add(&cmmb_device_cdev, dev, MAX_CMMB_MINORS)) != 0){\r
+               DBGERR("[CMMB HW]:[class]:[err]: cedv add fail!!!\n");\r
+               goto error;\r
+       }\r
+\r
+       cmmb_class = class_create(THIS_MODULE, "cmmb");\r
+       if (IS_ERR(cmmb_class)) {\r
+        DBGERR("[CMMB HW]:[class]:[err]: class creat fail!!!\n");\r
+               retval = PTR_ERR(cmmb_class);\r
+               goto error;\r
+       }\r
+\r
+    cmmb_register_adapter("cmmb_adapter", NULL);\r
+\r
+       return 0;\r
+\r
+error:\r
+       cdev_del(&cmmb_device_cdev);\r
+       unregister_chrdev_region(dev, MAX_CMMB_MINORS);\r
+       return retval;\r
+}\r
+\r
+\r
+static void __exit exit_cmmbclass(void)\r
+{\r
+    DBG("[CMMB HW]:[class]: exit_cmmbclass\n");\r
+\r
+    class_destroy(cmmb_class);\r
+       cdev_del(&cmmb_device_cdev);\r
+    cmmb_unregister_adapter(&CMMB_adapter);\r
+       unregister_chrdev_region(MKDEV(CMMB_MAJOR, 0), MAX_CMMB_MINORS);\r
+}\r
+\r
+\r
+subsys_initcall(init_cmmbclass);\r
+module_exit(exit_cmmbclass);\r
+\r
+MODULE_DESCRIPTION("CMMB CORE");\r
+MODULE_AUTHOR("HT,HZB,HH,LW");\r
+MODULE_LICENSE("GPL");\r
+\r
diff --git a/drivers/cmmb/cmmb_class.h b/drivers/cmmb/cmmb_class.h
new file mode 100755 (executable)
index 0000000..3294f55
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _CMMB_CLASS_H_\r
+#define _CMMB_CLASS_H_\r
+\r
+\r
+#include <linux/types.h>\r
+#include <linux/poll.h>\r
+#include <linux/fs.h>\r
+#include <linux/list.h>\r
+#include <linux/smp_lock.h>\r
+\r
+#define CMMB_MAJOR 200\r
+\r
+\r
+#define CMMB_DEVICE_TUNER   0\r
+#define CMMB_DEVICE_DEMO    1\r
+#define CMMB_DEVICE_DEMUX   2\r
+#define CMMB_DEVICE_CA      3\r
+#define CMMB_DEVICE_MEMO    4\r
+\r
+extern struct class * cmmb_class;\r
+\r
+struct cmmb_adapter {\r
+       int num;\r
+       struct list_head list_head;\r
+       struct list_head device_list;\r
+       const char *name;\r
+       void* priv;\r
+       struct device *device;\r
+};\r
+\r
+\r
+extern struct cmmb_adapter CMMB_adapter;\r
+struct cmmb_device {\r
+       struct list_head list_head;\r
+       struct file_operations *fops;\r
+       struct cmmb_adapter *adapter;\r
+       int type;\r
+       u32 id;\r
+\r
+       wait_queue_head_t         wait_queue;\r
+\r
+       int (*kernel_ioctl)(struct inode *inode, struct file *file,\r
+                           unsigned int cmd, void *arg);\r
+\r
+       void *priv;\r
+};\r
+\r
+\r
+int cmmb_register_device(struct cmmb_adapter *adap, struct cmmb_device **pcmmbdev,\r
+                        struct file_operations *fops, void *priv, int type,char* name);\r
+void cmmb_unregister_device(struct cmmb_device *cmmbdev);\r
+\r
+#define cmmb_attach(FUNCTION, ARGS...) ({ \\r
+       FUNCTION(ARGS); \\r
+\r
+\r
+#endif/* #ifndef _CMMB_CLASS_H_ */
\ No newline at end of file
diff --git a/drivers/cmmb/cmmb_memory.c b/drivers/cmmb/cmmb_memory.c
new file mode 100755 (executable)
index 0000000..f476877
--- /dev/null
@@ -0,0 +1,499 @@
+#include "cmmb_memory.h"\r
+#include "cmmb_class.h"\r
+#include <linux/errno.h>\r
+#include <linux/workqueue.h>\r
+#include <asm/atomic.h>\r
+\r
+#if 1\r
+#define DBGERR(x...)   printk(KERN_INFO x)\r
+#else\r
+#define DBGERR(x...)\r
+#endif\r
+\r
+#if 0\r
+#define DBG(x...)      printk(KERN_INFO x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+struct cmmb_memory CMMB_memo;\r
+static struct cmmb_device* cmmbmemo;\r
+\r
+\r
+static int cmmbmemo_release(struct inode *inode, struct file *file)\r
+{\r
+    struct cmmb_memory *cmmb_memo = (struct cmmb_memory*)file->private_data;\r
+    \r
+    DBG("[CMMB HW]:[memory]: enter cmmb av memory release\n");\r
+    \r
+    mutex_lock(&cmmb_memo->mutex);\r
+    \r
+       cmmb_memo->usr--;\r
+    \r
+       if(cmmb_memo->usr == 0){\r
+        kfree(cmmb_memo->video_buf);\r
+        kfree(cmmb_memo->audio_buf);\r
+        kfree(cmmb_memo->data_buf);\r
+               mutex_unlock(&cmmb_memo->mutex);\r
+        DBG("[CMMB HW]:[memory]: enter cmmb av memory release free buffer\n");\r
+       } else{\r
+               mutex_unlock(&cmmb_memo->mutex);\r
+       }    \r
+    return 0;\r
+}\r
+\r
+//hzb@20100416,ÔÚ´ò¿ªÉ豸µÄʱºòÉêÇë¿Õ¼ä\r
+static int cmmbmemo_open(struct inode * inode, struct file * file)\r
+{\r
+    struct cmmb_memory *cmmbmemo = &CMMB_memo;\r
+    int ret = 0;\r
+    \r
+    DBG("[CMMB HW]:[memory]: enter cmmb memo open\n");\r
+\r
+    if (mutex_lock_interruptible(&cmmbmemo->mutex))\r
+        return -ERESTARTSYS;\r
+    \r
+    cmmbmemo->usr++;\r
+    \r
+    if (cmmbmemo->usr == 1)\r
+    {\r
+        DBG("[CMMB HW]:[memory]:cmmb video buffer malloc\n");\r
+        \r
+        cmmbmemo->video_buf = NULL;\r
+        cmmbmemo->audio_buf = NULL;\r
+        cmmbmemo->data_buf  = NULL;\r
+\r
+        cmmbmemo->video_buf = kmalloc(CMMB_VIDEO_BUFFER_SIZE+1, GFP_KERNEL);\r
+\r
+        if (cmmbmemo->video_buf == NULL){\r
+            ret = - ENOMEM;\r
+            DBGERR("[CMMB HW]:[memory]:[err]: cmmb video buffer malloc fail!!!\n");\r
+            goto kmalloc_fail;\r
+        }\r
+\r
+        cmmbmemo->audio_buf = kmalloc(CMMB_AUDIO_BUFFER_SIZE+1, GFP_KERNEL);\r
+\r
+        if (cmmbmemo->audio_buf == NULL){\r
+            ret = - ENOMEM;\r
+            DBGERR("[CMMB HW]:[memory]:[err]: cmmb audio buffer malloc fail!!!\n");\r
+            goto kmalloc_fail;\r
+        }\r
+\r
+        cmmbmemo->data_buf = kmalloc(1, GFP_KERNEL);\r
+\r
+        if (cmmbmemo->data_buf == NULL){\r
+            ret = - ENOMEM;\r
+            DBGERR("[CMMB HW]:[memory]:[err]: cmmb data buffer malloc fail!!!\n");\r
+            goto kmalloc_fail;\r
+        }\r
+\r
+        //hzb@20100415,init av ring buffers,cmmb need three ring buffers to store the demuxed data\r
+        cmmb_ringbuffer_init(&cmmbmemo->buffer_Video, cmmbmemo->video_buf, CMMB_VIDEO_BUFFER_SIZE);  //init video ring buffer\r
+        cmmb_ringbuffer_init(&cmmbmemo->buffer_Audio, cmmbmemo->audio_buf, CMMB_AUDIO_BUFFER_SIZE);  //init audio ring buffer\r
+        cmmb_ringbuffer_init(&cmmbmemo->buffer_Data,  cmmbmemo->data_buf,  1);   //init data ring buffer\r
+\r
+        cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+        cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
+    }\r
+    file->private_data = cmmbmemo;  //hzb@20100415,store the cmmbmemo struct in the file private data \r
+    mutex_unlock(&cmmbmemo->mutex);    \r
+    return ret;\r
+        \r
+kmalloc_fail:\r
+    kfree(cmmbmemo->video_buf);\r
+    kfree(cmmbmemo->audio_buf);\r
+    kfree(cmmbmemo->data_buf);\r
+    mutex_unlock(&cmmbmemo->mutex);    \r
+    return ret;        \r
+}\r
+
+\r
+static ssize_t cmmbmemo_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)\r
+{\r
+    struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
+    ssize_t avail_V, avail_A, avail_D;\r
+    ssize_t ret;\r
+    \r
+    DBG("[CMMB HW]:[memory]:enter cmmb memory read\n");\r
+    \r
+    if (cmmbmemo->r_datatype == CMMB_VIDEO_TYPE){\r
+#if 0         \r
+        DECLARE_WAITQUEUE(wait, current);\r
+        for(;;){\r
+            avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+             \r
+            if (avail_V < count){          \r
+                add_wait_queue(&cmmbmemo->buffer_Video.queue, &wait);\r
+                __set_current_state(TASK_INTERRUPTIBLE);\r
+                schedule();\r
+                remove_wait_queue(&cmmbmemo->buffer_Video.queue, &wait);\r
+                if (signal_pending(current)){\r
+                   ret = -ERESTARTSYS;\r
+                   goto out2;\r
+                }\r
+            }\r
+        }\r
+#else\r
+#if 0\r
+        avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+        while (avail_V < count){\r
+            DBG("[CMMB HW]:[memory]:cmmb memory read video data sleep!!\n");\r
+            spin_lock(cmmbmemo->buffer_Video.lock);\r
+            cmmbmemo->buffer_Video.condition = 0;\r
+            spin_unlock(cmmbmemo->buffer_Video.lock);\r
+            if (wait_event_interruptible(cmmbmemo->buffer_Video.queue, cmmbmemo->buffer_Video.condition))\r
+                return -ERESTARTSYS;\r
+            \r
+            avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+            DBG("[CMMB HW]:[memory]:cmmb memory read video data awake\n");\r
+        }\r
+#endif \r
+           avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+           if (avail_V < count)  \r
+               return 0;     \r
+#endif          \r
+        ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Video, buf, count, 1);   
+     \r
+        DBG("[CMMB HW]:[memory]:cmmb memory video read ret = 0x%x\n",ret);\r
+    }else if (cmmbmemo->r_datatype == CMMB_AUDIO_TYPE){\r
+#if 0\r
+        DECLARE_WAITQUEUE(wait, current);\r
+        for(;;){\r
+            avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
+            if (avail_A < count){\r
+                add_wait_queue(&cmmbmemo->buffer_Audio.queue, &wait);\r
+                __set_current_state(TASK_INTERRUPTIBLE);\r
+                schedule();\r
+                remove_wait_queue(&cmmbmemo->buffer_Audio.queue, &wait);\r
+                if (signal_pending(current)){\r
+                    ret = -ERESTARTSYS;\r
+                    goto out2;\r
+                }\r
+            }\r
+        }\r
+#else\r
+#if 0\r
+        avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
+        while (avail_A < count){\r
+            DBG("[CMMB HW]:[memory]:cmmb memory read audio data sleep!!\n");\r
+            spin_lock(cmmbmemo->buffer_Audio.lock);\r
+            cmmbmemo->buffer_Audio.condition = 0;\r
+            spin_unlock(cmmbmemo->buffer_Audio.lock);\r
+            if (wait_event_interruptible(cmmbmemo->buffer_Audio.queue, cmmbmemo->buffer_Audio.condition))\r
+                return -ERESTARTSYS;\r
+            \r
+            avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
+            DBG("[CMMB HW]:[memory]:cmmb memory read audio data awake\n");\r
+        }\r
+#endif\r
+               avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);  \r
+               if (avail_A < count)  \r
+                       return 0;    \r
+#endif\r
+        ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Audio, buf, count, 1);\r
+    }else if(cmmbmemo->r_datatype == CMMB_DATA_TYPE){\r
+ #if 0   \r
+        DECLARE_WAITQUEUE(wait, current);\r
+        for(;;){\r
+           avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
+           if (avail_D < count){\r
+               add_wait_queue(&cmmbmemo->buffer_Data.queue, &wait);\r
+               __set_current_state(TASK_INTERRUPTIBLE);\r
+               schedule();\r
+               remove_wait_queue(&cmmbmemo->buffer_Data.queue, &wait);\r
+               if (signal_pending(current)){\r
+                   ret = -ERESTARTSYS;\r
+                   goto out2;\r
+               }\r
+           }\r
+        }\r
+#else\r
+#if 0\r
+        avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
+        while (avail_D < count){\r
+        DBG("[CMMB HW]:[memory]:cmmb memory read data sleep!!\n");\r
+        spin_lock(cmmbmemo->buffer_Data.lock);\r
+        cmmbmemo->buffer_Data.condition = 0;\r
+        spin_unlock(cmmbmemo->buffer_Data.lock);\r
+        if (wait_event_interruptible(cmmbmemo->buffer_Data.queue, cmmbmemo->buffer_Data.condition))\r
+            return -ERESTARTSYS;\r
+        \r
+        avail_D= cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
+        DBG("[CMMB HW]:[memory]:cmmb memory read data awake\n");\r
+        }\r
+#endif\r
+               avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);  \r
+               if (avail_D < count)  \r
+                       return 0;               \r
+#endif\r
+        ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Data, buf, count, 1);\r
+    }\r
+    \r
+out2:\r
+    cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
+    return ret;;\r
+}\r
+\r
+\r
+\r
+static ssize_t cmmbmemo_write(struct file *file, char __user *buf, size_t count,loff_t *ppos)\r
+{\r
+    struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
+    ssize_t free_V, free_A, free_D;\r
+    ssize_t ret;\r
+    static int loop = 0;\r
+    \r
+    DBG("[CMMB HW]:[memory]:enter cmmbdemux_write\n");\r
+    \r
+    if (cmmbmemo->w_datatype == CMMB_VIDEO_TYPE){\r
+        \r
+        free_V = cmmb_ringbuffer_free(&cmmbmemo->buffer_Video);\r
+        if (free_V >= count){\r
+           ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Video, buf, count);\r
+        }
+        //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+        spin_lock(cmmbmemo->buffer_Video.lock);\r
+        cmmbmemo->buffer_Video.condition = 1;\r
+        spin_unlock(cmmbmemo->buffer_Video.lock);\r
+        wake_up_interruptible(&cmmbmemo->buffer_Video.queue);\r
+    }else if (cmmbmemo->w_datatype == CMMB_AUDIO_TYPE){\r
+        free_A = cmmb_ringbuffer_free(&cmmbmemo->buffer_Audio);\r
+        if (free_A >= count){\r
+           ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Audio, buf, count);\r
+        }\r
+        //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+        spin_lock(cmmbmemo->buffer_Audio.lock);\r
+        cmmbmemo->buffer_Audio.condition = 1;\r
+        spin_unlock(cmmbmemo->buffer_Audio.lock);\r
+        wake_up_interruptible(&cmmbmemo->buffer_Audio.queue);\r
+    }else if(cmmbmemo->w_datatype == CMMB_DATA_TYPE){\r
+        free_D = cmmb_ringbuffer_free(&cmmbmemo->buffer_Data);\r
+        if (free_D >= count){\r
+           ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Data, buf, count);\r
+        }\r
+        //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+        spin_lock(cmmbmemo->buffer_Data.lock);\r
+        cmmbmemo->buffer_Data.condition = 1;\r
+        spin_unlock(cmmbmemo->buffer_Data.lock);\r
+        wake_up_interruptible(&cmmbmemo->buffer_Data.queue);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+\r
+int cmmbmemo_valueinit(struct file *file)\r
+{\r
+    struct cmmb_memory *cmmbmemo = file->private_data;\r
+    int ret = 0;\r
+\r
+    DBG("[CMMB HW]:[memory]: enter cmmb memo open\n");\r
+\r
+    cmmbmemo->video_buf = NULL;\r
+    cmmbmemo->audio_buf = NULL;\r
+    cmmbmemo->data_buf  = NULL;\r
+\r
+    cmmbmemo->video_buf = kzalloc(CMMB_VIDEO_BUFFER_SIZE+1, GFP_KERNEL);\r
+\r
+    if (cmmbmemo->video_buf == NULL){\r
+        ret = - ENOMEM;\r
+        DBGERR("[CMMB HW]:[memory]:[err]: cmmb video buffer malloc fail!!!\n");\r
+        goto kmalloc_fail;\r
+    }\r
+\r
+    cmmbmemo->audio_buf = kzalloc(CMMB_AUDIO_BUFFER_SIZE+1, GFP_KERNEL);\r
+\r
+    if (cmmbmemo->audio_buf == NULL){\r
+        ret = - ENOMEM;\r
+        DBGERR("[CMMB HW]:[memory]:[err]: cmmb audio buffer malloc fail!!!\n");\r
+        goto kmalloc_fail;\r
+    }\r
+\r
+    cmmbmemo->data_buf = kzalloc(1, GFP_KERNEL);\r
+\r
+    if (cmmbmemo->data_buf == NULL){\r
+        ret = - ENOMEM;\r
+        DBGERR("[CMMB HW]:[memory]:[err]: cmmb data buffer malloc fail!!!\n");\r
+        goto kmalloc_fail;\r
+    }\r
+\r
+    //hzb@20100415,init av ring buffers,cmmb need three ring buffers to store the demuxed data\r
+    cmmb_ringbuffer_init(&cmmbmemo->buffer_Video, cmmbmemo->video_buf, CMMB_VIDEO_BUFFER_SIZE);  //init video ring buffer\r
+    cmmb_ringbuffer_init(&cmmbmemo->buffer_Audio, cmmbmemo->audio_buf, CMMB_AUDIO_BUFFER_SIZE);  //init audio ring buffer\r
+    cmmb_ringbuffer_init(&cmmbmemo->buffer_Data,  cmmbmemo->data_buf,  1);   //init data ring buffer\r
+\r
+    cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+    cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
+\r
+    return ret;\r
+\r
+kmalloc_fail:\r
+    kfree(cmmbmemo->video_buf);\r
+    kfree(cmmbmemo->audio_buf);\r
+    kfree(cmmbmemo->data_buf);\r
+    return ret;   \r
+}\r
+\r
+static long cmmbmemo_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+    struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
+    long ret = 0;\r
+    \r
+    DBG("[CMMB HW]:[memory]:enter cmmbdemux_ioctl\n");\r
+\r
+    switch (cmd){\r
+           case CMMB_MEMO_WRITE:{\r
+            cmmbmemo->w_datatype = arg;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_MEMO_READ:{\r
+            cmmbmemo->r_datatype = arg;\r
+        }\r
+        break;\r
+\r
+        case CMMB_MEMO_FLUSH_ONE:{\r
+            if (arg == CMMB_VIDEO_TYPE){\r
+                cmmb_ringbuffer_flush(&cmmbmemo->buffer_Video);\r
+            }else if (arg == CMMB_AUDIO_TYPE){\r
+                cmmb_ringbuffer_flush(&cmmbmemo->buffer_Audio);\r
+            }else if (arg == CMMB_DATA_TYPE){\r
+                cmmb_ringbuffer_flush(&cmmbmemo->buffer_Data);\r
+            }else{\r
+                ret = - EINVAL;\r
+            }\r
+        }\r
+        break;\r
+       \r
+        case CMMB_MEMO_FLUSH_ALL:{\r
+            cmmb_ringbuffer_flush(&cmmbmemo->buffer_Video);\r
+            cmmb_ringbuffer_flush(&cmmbmemo->buffer_Audio);\r
+            cmmb_ringbuffer_flush(&cmmbmemo->buffer_Data);\r
+        }\r
+        break;\r
+        \r
+        case CMMB_MEMO_INIT:{\r
+            return cmmbmemo_valueinit(file);\r
+        }\r
+        break;\r
+\r
+        case CMMB_SET_VIDEO_TYPE:{\r
+            cmmbmemo->videotype = arg;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_SET_AUDIO_TYPE:{\r
+            cmmbmemo->audiotype = arg;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_SET_AUDIO_SAMPLE:{\r
+            cmmbmemo->audiosample = arg;\r
+        }\r
+        break;\r
+\r
+        case CMMB_GET_VIDEO_TYPE:{\r
+            return cmmbmemo->videotype;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_GET_AUDIO_TYPE:{\r
+            return cmmbmemo->videotype;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_GET_AUDIO_SAMPLE:{\r
+            return cmmbmemo->audiosample;\r
+        }\r
+        break;\r
+\r
+        case CMMB_GET_BUFF_FREE:{\r
+            if (arg == CMMB_VIDEO_TYPE){\r
+                ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Video);\r
+            }else if (arg == CMMB_AUDIO_TYPE){\r
+                ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Audio);\r
+            }else if (arg == CMMB_DATA_TYPE){\r
+                ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Data);\r
+            }else{\r
+                ret = - EINVAL;\r
+            }\r
+        }\r
+        break;\r
+\r
+        case CMMB_GET_BUFF_AVAIL:{\r
+            if (arg == CMMB_VIDEO_TYPE){\r
+                ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+            }else if (arg == CMMB_AUDIO_TYPE){\r
+                ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
+            }else if (arg == CMMB_DATA_TYPE){\r
+                ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
+            }else{\r
+                ret = - EINVAL;\r
+            }\r
+        }\r
+        break;\r
+        \r
+        default:\r
+            ;\r
+        break;\r
+    }\r
+    return ret;\r
+}\r
+\r
+static unsigned int cmmbmemo_poll(struct file *file, struct poll_table_struct *wait)\r
+{\r
+    struct cmmb_demux *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
+    unsigned int mask = 0;\r
+\r
+    DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
+    \r
+    //2todo memo poll, now doing nothing\r
+  \r
+    return mask;\r
+}\r
+\r
+\r
+static int cmmbmemo_mmap(struct file *file, struct vm_area_struct *vma)\r
+{\r
+    //2 todo memo mmmap, now doing nothing\r
+    DBG("[CMMB HW]:[memory]:enter cmmbdemux_ioctl\n");\r
+    return 0;\r
+}\r
+\r
+\r
+struct file_operations cmmbmemeo_fops = \r
+{\r
+    .open  = cmmbmemo_open,\r
+    .release = cmmbmemo_release,    \r
+    .read  = cmmbmemo_read,\r
+    .write = cmmbmemo_write,\r
+    .mmap  = cmmbmemo_mmap,\r
+    .poll  = cmmbmemo_poll,\r
+    .unlocked_ioctl = cmmbmemo_ioctl,\r
+};\r
+\r
+static int __init cmmbmemo_init(void)\r
+{\r
+    int res;\r
+    \r
+    DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
+       res =cmmb_register_device(&CMMB_adapter,&cmmbmemo, &cmmbmemeo_fops, NULL, CMMB_DEVICE_MEMO,"cmmb_memo");\r
+    mutex_init(&CMMB_memo.mutex);\r
+    CMMB_memo.usr = 0;\r
+    return res;\r
+}\r
+\r
+static void __exit cmmbmemo_exit(void)\r
+{\r
+    DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
+    cmmb_unregister_device(cmmbmemo);\r
+    //mutex_destroy(mutex);\r
+}\r
+\r
+module_init(cmmbmemo_init);\r
+module_exit(cmmbmemo_exit);\r
+\r
+MODULE_DESCRIPTION("CMMB demodulator general driver");\r
+MODULE_AUTHOR("HT,HZB,HH,LW");\r
+MODULE_LICENSE("GPL");\r
+\r
diff --git a/drivers/cmmb/cmmb_memory.h b/drivers/cmmb/cmmb_memory.h
new file mode 100755 (executable)
index 0000000..efd85ec
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _CMMB_AV_MEMORY_H_\r
+#define _CMMB_AV_MEMORY_H_\r
+\r
+#include <linux/module.h>\r
+#include <linux/interrupt.h>\r
+//#include <asm/semaphore.h>\r
+#include <linux/mutex.h>\r
+#include "cmmb_ringbuffer.h"\r
+\r
+\r
+#define   CMMB_MEMO_WRITE          (0x80000001)\r
+#define   CMMB_MEMO_READ           (0x80000002)\r
+#define   CMMB_MEMO_FLUSH_ONE      (0x80000003)\r
+#define   CMMB_MEMO_FLUSH_ALL      (0x80000004)\r
+#define   CMMB_MEMO_INIT           (0x80000005)\r
+#define   CMMB_SET_VIDEO_TYPE      (0x80000006)\r
+#define   CMMB_SET_AUDIO_TYPE      (0x80000007)\r
+#define   CMMB_SET_AUDIO_SAMPLE    (0x80000008)\r
+#define   CMMB_GET_VIDEO_TYPE      (0x80000009)\r
+#define   CMMB_GET_AUDIO_TYPE      (0x8000000a)\r
+#define   CMMB_GET_AUDIO_SAMPLE    (0x8000000b)\r
+#define   CMMB_GET_BUFF_FREE       (0x8000000c)\r
+#define   CMMB_GET_BUFF_AVAIL      (0x8000000d)\r
+\r
+\r
+struct cmmb_memory\r
+{\r
+    int  w_datatype;\r
+    int  r_datatype;\r
+    unsigned long  videotype;\r
+    unsigned long  audiotype;\r
+    unsigned long  audiosample;\r
+    int usr;\r
+\r
+    struct device *device;\r
+    struct file_operations* fops;\r
+    struct dvb_ringbuffer  buffer_Video;\r
+    struct dvb_ringbuffer  buffer_Audio;\r
+    struct dvb_ringbuffer  buffer_Data;\r
+    u8 *video_buf; \r
+    u8 *audio_buf; \r
+    u8 *data_buf; \r
+    \r
+    #define  CMMB_VIDEO_TYPE     0\r
+    #define  CMMB_AUDIO_TYPE     1\r
+    #define  CMMB_DATA_TYPE      2\r
+    #define  CMMB_NULL_TYPE      3\r
+    \r
+    #define CMMB_VIDEO_BUFFER_SIZE (512*1024)\r
+    #define CMMB_AUDIO_BUFFER_SIZE (64*1024)\r
+    #define CMMB_DATA_BUFFER_SIZE  (1*1024)\r
+\r
+       struct mutex mutex;\r
+    //struct semaphore sem;\r
+       spinlock_t lock;\r
+    wait_queue_head_t rqueue;\r
+    void* priv;\r
+};\r
+\r
+\r
+\r
+#endif/*_CMMBMEMORY_H_*/\r
+\r
+\r
diff --git a/drivers/cmmb/cmmb_ringbuffer.c b/drivers/cmmb/cmmb_ringbuffer.c
new file mode 100755 (executable)
index 0000000..0f97399
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ *
+ * dvb_ringbuffer.c: ring buffer implementation for the dvb driver
+ *
+ * Copyright (C) 2003 Oliver Endriss
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * based on code originally found in av7110.c & dvb_ci.c:
+ * Copyright (C) 1999-2003 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+#include "cmmb_ringbuffer.h"
+
+
+void cmmb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
+{
+       rbuf->pread=rbuf->pwrite=0;
+       rbuf->data=data;
+       rbuf->size=len;
+       rbuf->error=0;
+
+       init_waitqueue_head(&rbuf->queue);
+
+       spin_lock_init(&(rbuf->lock));
+    
+}
+
+
+
+int cmmb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
+{
+       return (rbuf->pread==rbuf->pwrite);
+}
+
+
+
+ssize_t cmmb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
+{
+       ssize_t free;
+
+       free = rbuf->pread - rbuf->pwrite;
+       if (free <= 0)
+               free += rbuf->size;
+       return free-1;
+}
+
+
+
+ssize_t cmmb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
+{
+       ssize_t avail;
+
+       avail = rbuf->pwrite - rbuf->pread;
+       if (avail < 0)
+               avail += rbuf->size;
+       return avail;
+}
+
+
+
+void cmmb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
+{
+       rbuf->pread = rbuf->pwrite;
+       rbuf->error = 0;
+}
+
+
+
+void cmmb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rbuf->lock, flags);
+       cmmb_ringbuffer_flush(rbuf);
+       spin_unlock_irqrestore(&rbuf->lock, flags);
+
+       wake_up(&rbuf->queue);
+}
+
+
+
+ssize_t cmmb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem)
+{
+       size_t todo = len;
+       size_t split;
+
+       split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+       if (split > 0) {
+               if (!usermem)
+                       memcpy(buf, rbuf->data+rbuf->pread, split);
+               else
+                       if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+                               return -EFAULT;
+               buf += split;
+               todo -= split;
+               rbuf->pread = 0;
+       }
+       if (!usermem)
+               memcpy(buf, rbuf->data+rbuf->pread, todo);
+       else
+               if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
+                       return -EFAULT;
+
+       rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+
+       return len;
+}
+
+
+
+ssize_t cmmb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
+{
+       size_t todo = len;
+       size_t split;
+
+       split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+
+       if (split > 0) {
+               memcpy(rbuf->data+rbuf->pwrite, buf, split);
+               buf += split;
+               todo -= split;
+               rbuf->pwrite = 0;
+       }
+       memcpy(rbuf->data+rbuf->pwrite, buf, todo);
+       rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+
+       return len;
+}
+
+
+
+
+EXPORT_SYMBOL(cmmb_ringbuffer_init);
+EXPORT_SYMBOL(cmmb_ringbuffer_empty);
+EXPORT_SYMBOL(cmmb_ringbuffer_free);
+EXPORT_SYMBOL(cmmb_ringbuffer_avail);
+EXPORT_SYMBOL(cmmb_ringbuffer_flush_spinlock_wakeup);
+EXPORT_SYMBOL(cmmb_ringbuffer_read);
+EXPORT_SYMBOL(cmmb_ringbuffer_write);
diff --git a/drivers/cmmb/cmmb_ringbuffer.h b/drivers/cmmb/cmmb_ringbuffer.h
new file mode 100755 (executable)
index 0000000..fea0079
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *
+ * dvb_ringbuffer.h: ring buffer implementation for the dvb driver
+ *
+ * Copyright (C) 2003 Oliver Endriss
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * based on code originally found in av7110.c & dvb_ci.c:
+ * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
+ *                         for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DVB_RINGBUFFER_H_1
+#define _DVB_RINGBUFFER_H_1
+
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+struct dvb_ringbuffer {
+       u8               *data;
+       ssize_t           size;
+       ssize_t           pread;
+       ssize_t           pwrite;
+       int               error;
+    volatile int      condition;
+       wait_queue_head_t queue;
+       spinlock_t        lock;
+};
+
+#define DVB_RINGBUFFER_PKTHDRSIZE 3
+
+
+/*
+** Notes:
+** ------
+** (1) For performance reasons read and write routines don't check buffer sizes
+**     and/or number of bytes free/available. This has to be done before these
+**     routines are called. For example:
+**
+**     *** write <buflen> bytes ***
+**     free = dvb_ringbuffer_free(rbuf);
+**     if (free >= buflen)
+**         count = dvb_ringbuffer_write(rbuf, buffer, buflen);
+**     else
+**         ...
+**
+**     *** read min. 1000, max. <bufsize> bytes ***
+**     avail = dvb_ringbuffer_avail(rbuf);
+**     if (avail >= 1000)
+**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize), 0);
+**     else
+**         ...
+**
+** (2) If there is exactly one reader and one writer, there is no need
+**     to lock read or write operations.
+**     Two or more readers must be locked against each other.
+**     Flushing the buffer counts as a read operation.
+**     Two or more writers must be locked against each other.
+*/
+
+/* initialize ring buffer, lock and queue */
+extern void cmmb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
+
+/* test whether buffer is empty */
+extern int cmmb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
+
+/* return the number of free bytes in the buffer */
+extern ssize_t cmmb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
+
+/* return the number of bytes waiting in the buffer */
+extern ssize_t cmmb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
+
+
+/* read routines & macros */
+/* ---------------------- */
+/* flush buffer */
+extern void cmmb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
+
+/* flush buffer protected by spinlock and wake-up waiting task(s) */
+extern void cmmb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
+
+/* peek at byte <offs> in the buffer */
+#define DVB_RINGBUFFER_PEEK(rbuf,offs) \
+                       (rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
+
+/* advance read ptr by <num> bytes */
+#define DVB_RINGBUFFER_SKIP(rbuf,num)  \
+                       (rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
+
+/*
+** read <len> bytes from ring buffer into <buf>
+** <usermem> specifies whether <buf> resides in user space
+** returns number of bytes transferred or -EFAULT
+*/
+extern ssize_t cmmb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
+                                  size_t len, int usermem);
+
+
+/* write routines & macros */
+/* ----------------------- */
+/* write single byte to ring buffer */
+#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte)   \
+                       { (rbuf)->data[(rbuf)->pwrite]=(byte); \
+                       (rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
+/*
+** write <len> bytes to ring buffer
+** <usermem> specifies whether <buf> resides in user space
+** returns number of bytes transferred or -EFAULT
+*/
+extern ssize_t cmmb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
+                                   size_t len);
+
+
+/**
+ * Write a packet into the ringbuffer.
+ *
+ * <rbuf> Ringbuffer to write to.
+ * <buf> Buffer to write.
+ * <len> Length of buffer (currently limited to 65535 bytes max).
+ * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
+ */
+
+
+#endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/cmmb/siano/Kconfig b/drivers/cmmb/siano/Kconfig
new file mode 100755 (executable)
index 0000000..7e00714
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config SMS_SIANO_MDTV
+       tristate "Siano SMS1xxx based MDTV receiver"
+       default y
+       ---help---
+       Choose Y or M here if you have MDTV receiver with a Siano chipset.
+
+       To compile this driver as a module, choose M here
+       (The modules will be called smsmdtv).
+
+       Note: All dependents, if selected, will be part of this module.
+
+       Further documentation on this driver can be found on the WWW at http://www.siano-ms.com/
+
+if SMS_SIANO_MDTV
+menu "Siano module components"
+
+# Kernel sub systems support
+
+config SMS_DVB3_SUBSYS
+       bool "DVB v.3 Subsystem support"
+       default n
+       ---help---
+       Choose if you would like to have DVB v.3 kernel sub-system support.
+
+config SMS_DVB5_S2API_SUBSYS
+       bool "DVB v.5 (S2 API) Subsystem support"
+       default n
+       ---help---
+       Choose if you would like to have DVB v.5 (S2 API) kernel sub-system support.
+
+config SMS_HOSTLIB_SUBSYS
+       bool "Host Library Subsystem support"
+       default y
+       ---help---
+       Choose if you would like to have Siano's host library kernel sub-system support.
+
+if SMS_HOSTLIB_SUBSYS
+
+config SMS_NET_SUBSYS
+       bool "Siano Network Adapter"
+       default n
+       ---help---
+       Choose if you would like to have Siano's network adapter support.
+
+endif # SMS_HOSTLIB_SUBSYS
+
+# Hardware interfaces support
+
+config SMS_USB_DRV
+       bool "USB interface support"
+       default n
+       ---help---
+       Choose if you would like to have Siano's support for USB interface
+
+config SMS_SDIO_DRV
+       bool "SDIO interface support"
+       default n
+       ---help---
+       Choose if you would like to have Siano's support for SDIO interface
+
+config SMS_SPI_ROCKCHIP
+       bool "Rockchip SPI interface support"
+       default y
+       ---help---
+       Choose if you would like to have Siano's support for Rockchip SPI interface
+
+endmenu
+endif # SMS_SIANO_MDTV
diff --git a/drivers/cmmb/siano/Makefile b/drivers/cmmb/siano/Makefile
new file mode 100755 (executable)
index 0000000..7ab5c21
--- /dev/null
@@ -0,0 +1,102 @@
+###############################################################################
+#
+# 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/>.
+#
+###############################################################################
+
+
+# Local variables initialization
+SMS_DVB3_SUBSYS := 0
+SMS_DVB5_S2API_SUBSYS := 0
+SMS_HOSTLIB_SUBSYS := 0
+
+SMS_USB_DRV := 0
+SMS_SDIO_DRV := 0
+SMS_SPI_PXA310_DRV := 0
+
+
+# Default object, include in every build variant
+SMSOBJ := smscoreapi.o sms-cards.o smsendian.o
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+
+
+# Kernel subsystems support
+ifdef CONFIG_SMS_DVB3_SUBSYS
+ifneq ($(CONFIG_SMS_DVB3_SUBSYS),n)
+SMS_DVB3_SUBSYS := 1
+EXTRA_CFLAGS += -DSMS_DVB3_SUBSYS -Idrivers/media/dvb/dvb-core
+SMSOBJ += smsdvb.o
+endif
+endif
+
+ifdef CONFIG_SMS_DVB5_S2API_SUBSYS
+ifneq ($(CONFIG_SMS_DVB5_S2API_SUBSYS),n)
+SMS_DVB5_S2API_SUBSYS := 1
+EXTRA_CFLAGS += -DSMS_DVB5_S2API_SUBSYS
+endif
+endif
+
+ifdef CONFIG_SMS_HOSTLIB_SUBSYS
+ifneq ($(CONFIG_SMS_HOSTLIB_SUBSYS),n)
+SMS_HOSTLIB_SUBSYS := 1
+EXTRA_CFLAGS += -DSMS_HOSTLIB_SUBSYS
+SMSOBJ += smschar.o
+endif
+endif
+
+ifdef CONFIG_SMS_NET_SUBSYS
+ifneq ($(CONFIG_SMS_NET_SUBSYS),n)
+SMS_NET_SUBSYS := 1
+EXTRA_CFLAGS += -DSMS_NET_SUBSYS
+SMSOBJ += smsnet.o
+endif
+endif
+
+# Hardware (host) interfaces support
+ifdef CONFIG_SMS_USB_DRV
+ifneq ($(CONFIG_SMS_USB_DRV),n)
+SMS_USB_DRV := 1
+EXTRA_CFLAGS += -DSMS_USB_DRV
+SMSOBJ += smsusb.o
+endif
+endif
+
+ifdef CONFIG_SMS_SDIO_DRV
+ifneq ($(CONFIG_SMS_SDIO_DRV),n)
+SMS_SDIO_DRV := 1
+EXTRA_CFLAGS += -DSMS_SDIO_DRV
+SMSOBJ += smssdio.o
+endif
+endif
+
+ifdef CONFIG_SMS_SPI_ROCKCHIP
+ifneq ($(CONFIG_SMS_SPI_ROCKCHIP),n)
+SMS_SPI_ROCKCHIP := 1
+EXTRA_CFLAGS += -DSMS_SPI_ROCKCHIP
+SMSOBJ += smsspilog.o smsspicommon.o smsspiphy_rk.o
+endif
+endif
+
+# All selected in one module named smsmdtv
+smsmdtv-objs := $(SMSOBJ)
+
+obj-$(CONFIG_SMS_SIANO_MDTV) := smsmdtv.o
+
+
+
diff --git a/drivers/cmmb/siano/compat.h b/drivers/cmmb/siano/compat.h
new file mode 100755 (executable)
index 0000000..5516960
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * $Id: compat.h,v 1.44 2006/01/15 09:35:16 mchehab Exp $
+ */
+
+#ifndef _COMPAT_H
+#define _COMPAT_H
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+#define        KERN_CONT       ""
+#endif
+
+/* To allow I2C compatibility code to work */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#include <linux/i2c-dev.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#ifdef CONFIG_PROC_FS
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#endif
+#endif
+
+/* To allow alsa code to work */
+#ifdef NEED_SOUND_DRIVER_H
+#include <sound/driver.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+#define set_freezable()
+#define cancel_delayed_work_sync cancel_rearming_delayed_work
+#endif
+
+#ifndef __pure
+#  define __pure __attribute__((pure))
+#endif
+
+#ifndef I2C_M_IGNORE_NAK
+# define I2C_M_IGNORE_NAK 0x1000
+#endif
+
+/* device_create/destroy added in 2.6.18 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+/* on older kernels, class_device_create will in turn be a compat macro */
+# define device_create(a, b, c, d, e, f, g) class_device_create(a, NULL, c, b, d, e, f, g)
+# define device_destroy(a, b) class_device_destroy(a, b)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#define IRQF_SHARED            SA_SHIRQ
+#define IRQF_DISABLED          SA_INTERRUPT
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+# define PCIAGP_FAIL 0
+
+#define vmalloc_32_user(a) vmalloc_32(a)
+
+#endif
+
+/* bool type and enum-based definition of true and false was added in 2.6.19 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+typedef int bool;
+#define true 1
+#define false 0
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+#define sony_pic_camera_command(a,b) sonypi_camera_command(a,b)
+
+#define SONY_PIC_COMMAND_SETCAMERAAGC        SONYPI_COMMAND_SETCAMERAAGC
+#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS SONYPI_COMMAND_SETCAMERABRIGHTNESS
+#define SONY_PIC_COMMAND_SETCAMERACOLOR      SONYPI_COMMAND_SETCAMERACOLOR
+#define SONY_PIC_COMMAND_SETCAMERACONTRAST   SONYPI_COMMAND_SETCAMERACONTRAST
+#define SONY_PIC_COMMAND_SETCAMERAHUE        SONYPI_COMMAND_SETCAMERAHUE
+#define SONY_PIC_COMMAND_SETCAMERAPICTURE    SONYPI_COMMAND_SETCAMERAPICTURE
+#define SONY_PIC_COMMAND_SETCAMERASHARPNESS  SONYPI_COMMAND_SETCAMERASHARPNESS
+#define SONY_PIC_COMMAND_SETCAMERA           SONYPI_COMMAND_SETCAMERA
+#endif
+
+/* pci_dev got a new revision field in 2.6.23-rc1 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) && defined(LINUX_PCI_H)
+/* Just make it easier to subsitute pci_dev->revision with
+ * v4l_compat_pci_rev(pci_dev).  It's too bad there isn't some kind of context
+ * sensitive macro in C that could do this for us.  */
+static inline u8 v4l_compat_pci_rev(struct pci_dev *pci)
+{ u8 rev; pci_read_config_byte(pci, PCI_REVISION_ID, &rev); return rev; }
+#endif
+
+#if defined(COMPAT_PCM_TO_RATE_BIT) && defined(__SOUND_PCM_H)
+/* New alsa core utility function */
+static inline unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
+{
+       static const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050,
+               32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 };
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(rates); i++)
+               if (rates[i] == rate)
+                       return 1u << i;
+       return SNDRV_PCM_RATE_KNOT;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+# define task_pid_nr(current) ((current)->pid)
+
+# define sg_init_table(a,b)
+# define sg_page(p) (sg->page)
+# define sg_set_page(sglist,pg,sz,off)                                 \
+do {                                                                   \
+       struct scatterlist *p=sglist;                                   \
+       p->page   = pg;                                                 \
+       p->length = sz;                                                 \
+       p->offset = off;                                                \
+} while (0)
+
+#define pr_err(fmt, arg...) \
+       printk(KERN_ERR fmt, ##arg)
+#endif
+
+#ifndef BIT_MASK
+# define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
+# define BIT_WORD(nr)            ((nr) / BITS_PER_LONG)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#define i2c_verify_client(dev) \
+       ((dev->bus == &i2c_bus_type) ? to_i2c_client(dev) : NULL)
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+#define i2c_verify_client(dev) \
+       ((dev->bus && 0 == strcmp(dev->bus->name, "i2c")) ? to_i2c_client(dev) : NULL)
+#endif
+
+#ifndef USB_DEVICE_AND_INTERFACE_INFO
+# define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+               | USB_DEVICE_ID_MATCH_DEVICE, \
+       .idVendor = (vend), .idProduct = (prod), \
+       .bInterfaceClass = (cl), \
+       .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#define get_unaligned_be16(a)                                  \
+       be16_to_cpu(get_unaligned((unsigned short *)(a)))
+#define put_unaligned_be16(r, a)                               \
+       put_unaligned(cpu_to_be16(r), ((unsigned short *)(a)))
+#define get_unaligned_le16(a)                                  \
+       le16_to_cpu(get_unaligned((unsigned short *)(a)))
+#define put_unaligned_le16(r, a)                               \
+       put_unaligned(cpu_to_le16(r), ((unsigned short *)(a)))
+#define get_unaligned_be32(a)                                  \
+       be32_to_cpu(get_unaligned((u32 *)(a)))
+#define put_unaligned_be32(r, a)                               \
+       put_unaligned(cpu_to_be32(r), ((u32 *)(a)))
+#define get_unaligned_le32(a)                                  \
+       le32_to_cpu(get_unaligned((u32 *)(a)))
+#define put_unaligned_le32(r, a)                               \
+       put_unaligned(cpu_to_le32(r), ((u32 *)(a)))
+#define get_unaligned_le64(a)                                  \
+       le64_to_cpu(get_unaligned((u64 *)(a)))
+#define put_unaligned_le64(r, a)                               \
+       put_unaligned(cpu_to_le64(r), ((u64 *)(a)))
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+#ifdef CONFIG_PROC_FS
+static inline struct proc_dir_entry *proc_create(const char *a,
+       mode_t b, struct proc_dir_entry *c, const struct file_operations *d)
+{
+       struct proc_dir_entry *e;
+
+       e = create_proc_entry(a, b, c);
+       if (e) {
+               e->owner = THIS_MODULE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
+               e->proc_fops = d;
+#else
+               e->proc_fops = (struct file_operations *)d;
+#endif
+       }
+       return e;
+}
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#ifdef CONFIG_PROC_FS
+static inline struct proc_dir_entry *proc_create_data(const char *a,
+       mode_t b, struct proc_dir_entry *c, const struct file_operations *d,
+       void *f)
+{
+       struct proc_dir_entry *e;
+
+       e = create_proc_entry(a, b, c);
+       if (e) {
+               e->owner = THIS_MODULE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
+               e->proc_fops = d;
+#else
+               e->proc_fops = (struct file_operations *)d;
+#endif
+               e->data = f;
+       }
+       return e;
+}
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
+#define hweight64(x)  generic_hweight64(x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#define div64_u64(a,b) div64_64(a,b)
+
+#define clamp( x, l, h )        max_t( __typeof__( x ),                \
+                                     ( l ),                    \
+                                     min_t( __typeof__( x ),   \
+                                            ( h ),             \
+                                            ( x ) ) )
+
+#define dev_name(dev)  ((dev)->bus_id)
+
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+typedef unsigned long uintptr_t;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+static inline int list_is_singular(const struct list_head *head)
+{
+        return !list_empty(head) && (head->next == head->prev);
+}
+#endif
+
+#endif
diff --git a/drivers/cmmb/siano/sms-cards.c b/drivers/cmmb/siano/sms-cards.c
new file mode 100755 (executable)
index 0000000..9caeef4
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ *  Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "sms-cards.h"
+
+struct usb_device_id smsusb_id_table[] = {
+       { USB_DEVICE(0x187f, 0x0010),
+               .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+       { USB_DEVICE(0x187f, 0x0100),
+               .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+       { USB_DEVICE(0x187f, 0x0200),
+               .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
+       { USB_DEVICE(0x187f, 0x0201),
+               .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
+       { USB_DEVICE(0x187f, 0x0300),
+               .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
+       { USB_DEVICE(0x2040, 0x1700),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
+       { USB_DEVICE(0x2040, 0x1800),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
+       { USB_DEVICE(0x2040, 0x1801),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
+       { USB_DEVICE(0x2040, 0x2000),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2009),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
+       { USB_DEVICE(0x2040, 0x200a),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2010),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2019),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x5500),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5510),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5520),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5530),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5580),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x2040, 0x5590),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+       { USB_DEVICE(0x187f, 0x0202),
+               .driver_info = SMS1XXX_BOARD_SIANO_NICE },
+       { USB_DEVICE(0x187f, 0x0301),
+               .driver_info = SMS1XXX_BOARD_SIANO_VENICE },
+       { } /* Terminating entry */
+       };
+
+MODULE_DEVICE_TABLE(usb, smsusb_id_table);
+
+static struct sms_board sms_boards[] = {
+       [SMS_BOARD_UNKNOWN] = {
+       /* 0 */
+               .name = "Unknown board",
+       },
+       [SMS1XXX_BOARD_SIANO_STELLAR] = {
+       /* 1 */
+               .name =
+               "Siano Stellar Digital Receiver",
+               .type = SMS_STELLAR,
+               .fw[DEVICE_MODE_DVBT_BDA] =
+               "sms1xxx-stellar-dvbt-01.fw",
+       },
+       [SMS1XXX_BOARD_SIANO_NOVA_A] = {
+       /* 2 */
+               .name = "Siano Nova A Digital Receiver",
+               .type = SMS_NOVA_A0,
+               .fw[DEVICE_MODE_DVBT_BDA] =
+               "sms1xxx-nova-a-dvbt-01.fw",
+       },
+       [SMS1XXX_BOARD_SIANO_NOVA_B] = {
+       /* 3 */
+               .name = "Siano Nova B Digital Receiver",
+               .type = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] =
+               "sms1xxx-nova-b-dvbt-01.fw",
+       },
+       [SMS1XXX_BOARD_SIANO_VEGA] = {
+       /* 4 */
+               .name = "Siano Vega Digital Receiver",
+               .type = SMS_VEGA,
+       },
+       [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
+       /* 5 */
+               .name = "Hauppauge Catamount",
+               .type = SMS_STELLAR,
+               .fw[DEVICE_MODE_DVBT_BDA] =
+               "sms1xxx-stellar-dvbt-01.fw",
+       },
+       [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
+       /* 6 */
+               .name = "Hauppauge Okemo-A",
+               .type = SMS_NOVA_A0,
+               .fw[DEVICE_MODE_DVBT_BDA] =
+               "sms1xxx-nova-a-dvbt-01.fw",
+       },
+       [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
+       /* 7 */
+               .name = "Hauppauge Okemo-B",
+               .type = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] =
+               "sms1xxx-nova-b-dvbt-01.fw",
+       },
+       [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
+       /* 8 */
+               .name = "Hauppauge WinTV MiniStick",
+               .type = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+               .board_cfg.leds_power = 26,
+               .board_cfg.led0 = 27,
+               .board_cfg.led1 = 28,
+       },
+       [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
+       /* 9 */
+               .name = "Hauppauge WinTV MiniCard",
+               .type = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+               .board_cfg.foreign_lna0_ctrl = 29,
+       },
+       [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
+       /* 10 */
+               .name = "Hauppauge WinTV MiniCard",
+               .type = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+               .board_cfg.foreign_lna0_ctrl = 1,
+       },
+       [SMS1XXX_BOARD_SIANO_NICE] = {
+       /* 11 */
+               .name = "Siano Nice Digital Receiver",
+               .type = SMS_NOVA_B0,
+       },
+       [SMS1XXX_BOARD_SIANO_VENICE] = {
+       /* 12 */
+               .name = "Siano Venice Digital Receiver",
+               .type = SMS_VEGA,
+       },
+};
+
+struct sms_board *sms_get_board(int id)
+{
+       BUG_ON(id >= ARRAY_SIZE(sms_boards));
+       return &sms_boards[id];
+}
+
+static inline void sms_gpio_assign_11xx_default_led_config(
+               struct smscore_gpio_config *pGpioConfig) {
+       pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
+       pGpioConfig->InputCharacteristics =
+               SMS_GPIO_INPUTCHARACTERISTICS_NORMAL;
+       pGpioConfig->OutputDriving = SMS_GPIO_OUTPUTDRIVING_4mA;
+       pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUTSLEWRATE_0_45_V_NS;
+       pGpioConfig->PullUpDown = SMS_GPIO_PULLUPDOWN_NONE;
+}
+
+int sms_board_event(struct smscore_device_t *coredev,
+               enum SMS_BOARD_EVENTS gevent) {
+       int board_id = smscore_get_board_id(coredev);
+       struct sms_board *board = sms_get_board(board_id);
+       struct smscore_gpio_config MyGpioConfig;
+
+       sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
+
+       switch (gevent) {
+       case BOARD_EVENT_POWER_INIT: /* including hotplug */
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       /* set I/O and turn off all LEDs */
+                       smscore_gpio_configure(coredev,
+                                       board->board_cfg.leds_power,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.leds_power, 0);
+                       smscore_gpio_configure(coredev, board->board_cfg.led0,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.led0, 0);
+                       smscore_gpio_configure(coredev, board->board_cfg.led1,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       /* set I/O and turn off LNA */
+                       smscore_gpio_configure(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       0);
+                       break;
+               }
+               break; /* BOARD_EVENT_BIND */
+
+       case BOARD_EVENT_POWER_SUSPEND:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.leds_power, 0);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led0, 0);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       0);
+                       break;
+               }
+               break; /* BOARD_EVENT_POWER_SUSPEND */
+
+       case BOARD_EVENT_POWER_RESUME:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.leds_power, 1);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led0, 1);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       1);
+                       break;
+               }
+               break; /* BOARD_EVENT_POWER_RESUME */
+
+       case BOARD_EVENT_BIND:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.leds_power, 1);
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.led0, 1);
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       1);
+                       break;
+               }
+               break; /* BOARD_EVENT_BIND */
+
+       case BOARD_EVENT_SCAN_PROG:
+               break; /* BOARD_EVENT_SCAN_PROG */
+       case BOARD_EVENT_SCAN_COMP:
+               break; /* BOARD_EVENT_SCAN_COMP */
+       case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
+               break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
+       case BOARD_EVENT_FE_LOCK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                       board->board_cfg.led1, 1);
+                       break;
+               }
+               break; /* BOARD_EVENT_FE_LOCK */
+       case BOARD_EVENT_FE_UNLOCK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               }
+               break; /* BOARD_EVENT_FE_UNLOCK */
+       case BOARD_EVENT_DEMOD_LOCK:
+               break; /* BOARD_EVENT_DEMOD_LOCK */
+       case BOARD_EVENT_DEMOD_UNLOCK:
+               break; /* BOARD_EVENT_DEMOD_UNLOCK */
+       case BOARD_EVENT_RECEPTION_MAX_4:
+               break; /* BOARD_EVENT_RECEPTION_MAX_4 */
+       case BOARD_EVENT_RECEPTION_3:
+               break; /* BOARD_EVENT_RECEPTION_3 */
+       case BOARD_EVENT_RECEPTION_2:
+               break; /* BOARD_EVENT_RECEPTION_2 */
+       case BOARD_EVENT_RECEPTION_1:
+               break; /* BOARD_EVENT_RECEPTION_1 */
+       case BOARD_EVENT_RECEPTION_LOST_0:
+               break; /* BOARD_EVENT_RECEPTION_LOST_0 */
+       case BOARD_EVENT_MULTIPLEX_OK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 1);
+                       break;
+               }
+               break; /* BOARD_EVENT_MULTIPLEX_OK */
+       case BOARD_EVENT_MULTIPLEX_ERRORS:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               }
+               break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
+
+       default:
+               sms_err("Unknown SMS board event");
+               break;
+       }
+       return 0;
+}
diff --git a/drivers/cmmb/siano/sms-cards.h b/drivers/cmmb/siano/sms-cards.h
new file mode 100755 (executable)
index 0000000..be7bc8e
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SMS_CARDS_H__
+#define __SMS_CARDS_H__
+
+#include <linux/usb.h>
+#include "smscoreapi.h"
+
+#define SMS_BOARD_UNKNOWN 0
+#define SMS1XXX_BOARD_SIANO_STELLAR 1
+#define SMS1XXX_BOARD_SIANO_NOVA_A  2
+#define SMS1XXX_BOARD_SIANO_NOVA_B  3
+#define SMS1XXX_BOARD_SIANO_VEGA    4
+#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
+#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
+#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
+#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
+#define SMS1XXX_BOARD_SIANO_NICE       11
+#define SMS1XXX_BOARD_SIANO_VENICE     12
+
+struct sms_board_gpio_cfg {
+       int foreign_lna0_ctrl;
+       int foreign_lna1_ctrl;
+       int foreign_lna2_ctrl;
+       int lna_vhf_exist;
+       int lna_vhf_ctrl;
+       int lna_uhf_exist;
+       int lna_uhf_ctrl;
+       int lna_uhf_d_ctrl;
+       int lna_sband_exist;
+       int lna_sband_ctrl;
+       int lna_sband_d_ctrl;
+       int leds_power;
+       int led0;
+       int led1;
+       int led2;
+       int led3;
+       int led4;
+       int ir;
+       int eeprom_wp;
+       int mrc_sense;
+       int mrc_pdn_resetn;
+       int mrc_gp0; /* mrcs spi int */
+       int mrc_gp1;
+       int mrc_gp2;
+       int mrc_gp3;
+       int mrc_gp4;
+       int host_spi_gsp_ts_int;
+};
+
+struct sms_board {
+       enum sms_device_type_st type;
+       char *name, *fw[DEVICE_MODE_MAX];
+       struct sms_board_gpio_cfg board_cfg;
+};
+
+struct sms_board *sms_get_board(int id);
+
+extern struct usb_device_id smsusb_id_table[];
+extern struct smscore_device_t *coredev;
+
+enum SMS_BOARD_EVENTS {
+       BOARD_EVENT_POWER_INIT,
+       BOARD_EVENT_POWER_SUSPEND,
+       BOARD_EVENT_POWER_RESUME,
+       BOARD_EVENT_BIND,
+       BOARD_EVENT_SCAN_PROG,
+       BOARD_EVENT_SCAN_COMP,
+       BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
+       BOARD_EVENT_FE_LOCK,
+       BOARD_EVENT_FE_UNLOCK,
+       BOARD_EVENT_DEMOD_LOCK,
+       BOARD_EVENT_DEMOD_UNLOCK,
+       BOARD_EVENT_RECEPTION_MAX_4,
+       BOARD_EVENT_RECEPTION_3,
+       BOARD_EVENT_RECEPTION_2,
+       BOARD_EVENT_RECEPTION_1,
+       BOARD_EVENT_RECEPTION_LOST_0,
+       BOARD_EVENT_MULTIPLEX_OK,
+       BOARD_EVENT_MULTIPLEX_ERRORS
+};
+
+int sms_board_event(struct smscore_device_t *coredev,
+               enum SMS_BOARD_EVENTS gevent);
+
+#endif /* __SMS_CARDS_H__ */
diff --git a/drivers/cmmb/siano/smschar.c b/drivers/cmmb/siano/smschar.c
new file mode 100755 (executable)
index 0000000..d949f38
--- /dev/null
@@ -0,0 +1,808 @@
+/****************************************************************
+
+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 <asm/arch/mfp-pxa9xx.h>
+//#include <asm/arch/mfp-pxa3xx.h>
+//#include <asm/arch/gpio.h>
+#include "smscoreapi.h"
+
+#include "smscharioctl.h"
+#ifdef CONFIG_ANDROID_POWER
+#include <linux/android_power.h>
+#endif
+
+/* 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 = 0;
+
+/*!  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 =0 ;
+
+static int g_pnp_status_changed = 1;
+//wait_queue_head_t g_pnp_event;
+
+static struct class *smschr_dev_class;
+static int g_has_suspended =0 ;
+static struct device* sms_power_dev ;
+
+int        sms_suspend_count  ;
+static struct     semaphore sem;
+static int        g_has_opened=0;
+static int        g_has_opened_first=0;
+static int resume_flag=0;
+/**
+ * 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;
+
+       sms_info("entering... smschar_unregister_client....\n");
+       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);
+// only fr test , hzb
+//     return 0;
+       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;
+
+       // if(g_has_suspended)
+         //  return rc;
+
+       sms_info("entering index %d\n", dev->device_index);
+
+       if (dev->coredev) {
+               struct smsclient_params_t params;
+      #if 1
+
+               if(g_has_opened_first==0 && dev->device_index==0)
+               {
+
+                smsspi_poweron();
+                g_has_opened_first=1;
+                printk("open first********\n");
+    }
+    else if(dev->device_index!=0)
+        g_has_opened_first=0;
+      /****************end*******************************/ 
+#endif    
+      
+       //      down(&sem);
+               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;
+           g_has_opened++;     
+       //      up(&sem);
+       }
+  
+       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)
+{
+       struct smschar_device_t *dev = file->private_data;
+/*        if(g_has_suspended ){
+            printk(KERN_EMERG "SMS1180: suspenede has released all client\n");
+            return 0;
+        }
+*/
+    //printk("release smschar,%d\n",g_has_opened);
+
+       smschar_unregister_client(file->private_data);
+#if 1
+    if(!(--g_has_opened)&& (g_has_opened_first==0))//hzb rockchip@20100528 g_has_opened_first==0??????????
+    {
+        smscore_reset_device_drvs(dev->coredev);
+        smsspi_off();
+        g_has_opened_first = 0;
+        printk("release at the end******\n");
+    }
+/*****************end**************************/
+#endif
+       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||g_has_suspended) {
+               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||g_has_suspended) {
+               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);
+
+
+       memset(touser, 0, sizeof(struct smschar_buffer_t));
+
+       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;
+       }
+
+        //sms_debug("offset %d, size %d", touser->offset,touser->size);
+     
+       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||g_has_suspended) {
+               sms_err("no client\n");
+               return -ENODEV;
+       }
+    
+//     sms_info("smscharioctl - command is 0x%x", cmd);
+       switch (cmd) {
+       case SMSCHAR_STARTUP:
+                smsspi_poweron();
+               return 0;
+       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:
+               {
+                       printk("pnp event not supported\n") ;
+#if 0
+                       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;
+#endif 
+                       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;
+                       //sms_debug(" before wait_get_buffer"); 
+                       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;
+                       //sms_debug(" after wait_get_buffer");  
+
+                       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);
+               }
+       // leadcore add on 2010-01-07
+       case  SMSCHAR_GET_RESUME_FLAG:
+                copy_to_user(up, &resume_flag, sizeof(int));
+                return 0;
+                 
+       case  SMSCHAR_SET_RESUME_FLAG:
+                copy_from_user(&resume_flag,up,sizeof(int));
+            return 0;
+
+                 
+       case  SMSCHAR_RESET_DEVICE_DRVS:
+         smsspi_off();
+            return  smscore_reset_device_drvs (dev->coredev);
+
+       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)
+{
+       //struct device *smschr_dev;
+       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);
+       
+       if (!index)
+               device_create(smschr_dev_class, NULL, devno,NULL,"mdtvctrl");
+       else
+               device_create(smschr_dev_class, NULL, devno, NULL,"mdtv%d", index);
+       
+       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 */
+}
+
+void smschar_reset_device(void)
+{
+    int i;
+    printk(KERN_EMERG "SMS1180:in smschar_reset_device\n") ;
+    for(i=0;i< SMSCHAR_NR_DEVS;i++)
+    {
+        smschar_devices[i].cancel_waitq = 1;
+        wake_up_interruptible(&smschar_devices[i].waitq) ;
+        smschar_unregister_client(&smschar_devices[i]) ;
+    }
+}
+void smschar_set_suspend(int suspend_on)// 1: suspended ,0:resume  
+{
+    printk(KERN_EMERG "SMS1180 : suspend_on = %d\n",suspend_on) ;
+    if(suspend_on) 
+       g_has_suspended = 1;
+    else 
+       g_has_suspended = 0;
+}
+
+EXPORT_SYMBOL(smschar_reset_device) ;
+EXPORT_SYMBOL(smschar_set_suspend) ;
+
+static ssize_t
+sms_suspend_state_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+    return sprintf(buf,"%d",sms_suspend_count) ;
+}
+static ssize_t
+sms_suspend_state_store(struct device *dev, struct device_attribute *attr,
+               const char *buffer, size_t count) 
+{
+    sms_suspend_count =0 ;
+    return count ;
+}
+
+static DEVICE_ATTR(suspend,S_IRUGO|S_IWUGO,sms_suspend_state_show,sms_suspend_state_store);
+
+#ifdef CONFIG_PM
+#ifdef CONFIG_ANDROID_POWER
+void smsspi_android_suspend_handler(android_early_suspend_t *h)
+{
+}
+
+void smsspi_android_resume_handler(android_early_suspend_t *h)
+{
+         int value;
+         if(g_has_opened)
+         {
+         resume_flag=1;
+         }
+         else
+         resume_flag=0;
+}
+static android_early_suspend_t smsspi_android_suspend = {
+       .level = 5,
+       .suspend = smsspi_android_suspend_handler,
+       .resume = smsspi_android_resume_handler,
+};
+#endif
+#endif /*CONFIG_PM */
+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);
+
+       smschr_dev_class = class_create(THIS_MODULE, "smsmdtv");
+       if(IS_ERR(smschr_dev_class)){
+               sms_err("Could not create sms char device class\n");
+               return -1;
+       }
+        sms_power_dev = device_create(smschr_dev_class,NULL,0,"%s","power_state") ;
+        if(sms_power_dev)
+        {
+           rc = device_create_file(sms_power_dev, &dev_attr_suspend) ;
+        }
+       //android_register_early_suspend(&smsspi_android_suspend);//hzb 
+       return smscore_register_hotplug(smschar_hotplug);
+}
+
+void smschar_unregister(void)
+{
+       dev_t devno = MKDEV(smschar_major, smschar_minor);
+       
+       int i;
+       for( i = 0; i < SMSCHAR_NR_DEVS; i++)
+               device_destroy(smschr_dev_class, MKDEV(smschar_major, i));
+       class_destroy(smschr_dev_class);
+
+       unregister_chrdev_region(devno, SMSCHAR_NR_DEVS);
+       smscore_unregister_hotplug(smschar_hotplug);
+       //android_unregister_early_suspend(&smsspi_android_suspend);
+       sms_info("unregistered\n");
+}
diff --git a/drivers/cmmb/siano/smscharioctl.h b/drivers/cmmb/siano/smscharioctl.h
new file mode 100755 (executable)
index 0000000..ccefaa8
--- /dev/null
@@ -0,0 +1,55 @@
+/****************************************************************
+
+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)
+#define SMSCHAR_RESET_DEVICE_DRVS      _IO('K', 8)
+#define SMSCHAR_STARTUP                        _IO('K', 9)
+#define SMSCHAR_GET_RESUME_FLAG     _IO('K', 10)
+#define SMSCHAR_SET_RESUME_FLAG     _IO('K', 11)
+#endif /* __SMS_CHAR_IOCTL_H__ */
diff --git a/drivers/cmmb/siano/smscoreapi.c b/drivers/cmmb/siano/smscoreapi.c
new file mode 100755 (executable)
index 0000000..150cbc3
--- /dev/null
@@ -0,0 +1,2015 @@
+/****************************************************************
+
+ 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <linux/firmware.h>
+#include <asm/byteorder.h>
+
+#include "smscoreapi.h"
+#include "smsendian.h"
+#include "sms-cards.h"
+#include <mach/gpio.h>
+
+#define MAX_GPIO_PIN_NUMBER    31
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
+//#define REQUEST_FIRMWARE_SUPPORTED
+#undef REQUEST_FIRMWARE_SUPPORTED
+//#define DEFAULT_FW_FILE_PATH "/opl/usr/firmware/"
+#define DEFAULT_FW_FILE_PATH "/etc/firmware/"
+#else
+//#define DEFAULT_FW_FILE_PATH "/lib/firmware"
+//#define DEFAULT_FW_FILE_PATH "/opl/usr/firmware/"
+#define DEFAULT_FW_FILE_PATH "/etc/firmware/"
+#endif
+
+// to enable log
+int sms_debug =7;
+//int sms_debug =0;   //hzb 0526
+// for loopback
+char g_LbResBuf[256]={0};
+//
+module_param_named(debug, sms_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+//static int default_mode = 4;
+static int default_mode = DEVICE_MODE_CMMB;
+module_param(default_mode, int, 0644);
+MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
+
+struct smscore_device_notifyee_t {
+       struct list_head entry;
+       hotplug_t hotplug;
+};
+
+struct smscore_idlist_t {
+       struct list_head entry;
+       int id;
+       int data_type;
+};
+
+struct smscore_client_t {
+       struct list_head entry;
+       struct smscore_device_t *coredev;
+       void *context;
+       struct list_head idlist;
+       onresponse_t onresponse_handler;
+       onremove_t onremove_handler;
+};
+
+struct smscore_device_t {
+       struct list_head entry;
+
+       struct list_head clients;
+       struct list_head subclients;
+       spinlock_t clientslock;
+
+       struct list_head buffers;
+       spinlock_t bufferslock;
+       int num_buffers;
+
+       void *common_buffer;
+       int common_buffer_size;
+       dma_addr_t common_buffer_phys;
+
+       void *context;
+       struct device *device;
+
+       char devpath[32];
+       unsigned long device_flags;
+
+       setmode_t setmode_handler;
+       detectmode_t detectmode_handler;
+       sendrequest_t sendrequest_handler;
+       preload_t preload_handler;
+       postload_t postload_handler;
+
+       int mode, modes_supported;
+
+       struct completion version_ex_done, data_download_done, trigger_done;
+       struct completion init_device_done, reload_start_done, resume_done;
+       struct completion gpio_configuration_done, gpio_set_level_done;
+       struct completion gpio_get_level_done;
+// for loopback        
+       struct completion loopback_res_done;
+// for loopback
+       int gpio_get_res;
+
+       int board_id;
+
+       u8 *fw_buf;
+       u32 fw_buf_size;
+
+       wait_queue_head_t buffer_mng_waitq;
+};
+
+
+
+
+static struct smscore_device_t* panic_core_dev = NULL ;
+
+void smscore_panic_print(void)
+{
+    if(panic_core_dev)
+    {
+        printk("common_buffer_size  = [0x%x]\n", panic_core_dev-> common_buffer_size) ;
+        printk("common_buffer start addr= [0x%x]\n",(unsigned int) panic_core_dev->common_buffer ) ;
+        printk("common_buffer end  addr= [0x%x]\n",
+                   (unsigned int) (panic_core_dev->common_buffer + panic_core_dev-> common_buffer_size -1)) ;
+        printk("common_buffer_phys start addr = [0x%x]\n",(unsigned int) panic_core_dev->common_buffer_phys) ;
+        printk("common_buffer_phys end addr = [0x%x]\n",
+                  (unsigned int)  ( panic_core_dev->common_buffer_phys+ panic_core_dev-> common_buffer_size -1)) ;
+    }
+}
+
+// 
+// for loopback
+
+int  AdrLoopbackTest( struct smscore_device_t *coredev );
+
+void smscore_set_board_id(struct smscore_device_t *core, int id)
+{
+       core->board_id = id;
+}
+
+int smscore_get_board_id(struct smscore_device_t *core)
+{
+       return core->board_id;
+}
+
+struct smscore_registry_entry_t {
+       struct list_head entry;
+       char devpath[32];
+       int mode;
+       enum sms_device_type_st type;
+};
+
+static struct list_head g_smscore_notifyees;
+static struct list_head g_smscore_devices;
+static struct mutex g_smscore_deviceslock;
+static struct list_head g_smscore_registry;
+static struct mutex g_smscore_registrylock;
+
+static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
+{
+       struct smscore_registry_entry_t *entry;
+       struct list_head *next;
+
+       kmutex_lock(&g_smscore_registrylock);
+       for (next = g_smscore_registry.next; next != &g_smscore_registry; next
+                       = next->next) {
+               entry = (struct smscore_registry_entry_t *) next;
+               if (!strcmp(entry->devpath, devpath)) {
+                       kmutex_unlock(&g_smscore_registrylock);
+                       return entry;
+               }
+       }
+       entry = /* (struct smscore_registry_entry_t *) */kmalloc(
+                       sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
+       if (entry) {
+               entry->mode = default_mode;
+               if(strlen(devpath) >= 32)
+               {
+                       sms_err(" strlen(devpath) >= 32\n");
+                       return NULL;
+               }
+               strcpy(entry->devpath, devpath);
+               list_add(&entry->entry, &g_smscore_registry);
+       } else
+               sms_err("failed to create smscore_registry.");
+       kmutex_unlock(&g_smscore_registrylock);
+       return entry;
+}
+
+int smscore_registry_getmode(char *devpath)
+{
+       struct smscore_registry_entry_t *entry;
+
+       entry = smscore_find_registry(devpath);
+       if (entry)
+               return entry->mode;
+       else
+               sms_err("No registry found.");
+
+       return default_mode;
+}
+
+static enum sms_device_type_st smscore_registry_gettype(char *devpath)
+{
+       struct smscore_registry_entry_t *entry;
+
+       entry = smscore_find_registry(devpath);
+       if (entry)
+               return entry->type;
+       else
+               sms_err("No registry found.");
+
+       return -1;
+}
+
+void smscore_registry_setmode(char *devpath, int mode)
+{
+       struct smscore_registry_entry_t *entry;
+
+       entry = smscore_find_registry(devpath);
+       if (entry)
+               entry->mode = mode;
+       else
+               sms_err("No registry found.");
+}
+
+static void smscore_registry_settype(char *devpath,
+               enum sms_device_type_st type) {
+       struct smscore_registry_entry_t *entry;
+
+       entry = smscore_find_registry(devpath);
+       if (entry)
+               entry->type = type;
+       else
+               sms_err("No registry found.");
+}
+
+static void list_add_locked(struct list_head *new, struct list_head *head,
+               spinlock_t *lock) {
+       unsigned long flags;
+
+       spin_lock_irqsave(lock, flags);
+       list_add(new, head);
+       spin_unlock_irqrestore(lock, flags);
+}
+
+/**
+ * register a client callback that called when device plugged in/unplugged
+ * NOTE: if devices exist callback is called immediately for each device
+ *
+ * @param hotplug callback
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_hotplug(hotplug_t hotplug)
+{
+       struct smscore_device_notifyee_t *notifyee;
+       struct list_head *next, *first;
+       int rc = 0;
+
+       sms_info(" entering... smscore_register_hotplug \n");
+       kmutex_lock(&g_smscore_deviceslock);
+
+       notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
+               GFP_KERNEL);
+       if (notifyee) {
+               /* now notify callback about existing devices */
+               first = &g_smscore_devices;
+               for (next = first->next; next != first && !rc;
+                       next = next->next) {
+                       struct smscore_device_t *coredev =
+                               (struct smscore_device_t *) next;
+                       rc = hotplug(coredev, coredev->device, 1);
+               }
+
+               if (rc >= 0) {
+                       notifyee->hotplug = hotplug;
+                       list_add(&notifyee->entry, &g_smscore_notifyees);
+               } else
+                       kfree(notifyee);
+       } else
+               rc = -ENOMEM;
+
+       kmutex_unlock(&g_smscore_deviceslock);
+
+       return rc;
+}
+
+/**
+ * unregister a client callback that called when device plugged in/unplugged
+ *
+ * @param hotplug callback
+ *
+ */
+void smscore_unregister_hotplug(hotplug_t hotplug)
+{
+       struct list_head *next, *first;
+
+       kmutex_lock(&g_smscore_deviceslock);
+
+       first = &g_smscore_notifyees;
+
+       for (next = first->next; next != first;) {
+               struct smscore_device_notifyee_t *notifyee =
+                               (struct smscore_device_notifyee_t *) next;
+               next = next->next;
+
+               if (notifyee->hotplug == hotplug) {
+                       list_del(&notifyee->entry);
+                       kfree(notifyee);
+               }
+       }
+
+       kmutex_unlock(&g_smscore_deviceslock);
+}
+
+static void smscore_notify_clients(struct smscore_device_t *coredev)
+{
+       struct smscore_client_t *client;
+
+       /* the client must call smscore_unregister_client from remove handler */
+       while (!list_empty(&coredev->clients)) {
+               client = (struct smscore_client_t *) coredev->clients.next;
+               client->onremove_handler(client->context);
+       }
+}
+
+static int smscore_notify_callbacks(struct smscore_device_t *coredev,
+               struct device *device, int arrival) {
+       struct list_head *next, *first;
+       int rc = 0;
+
+       /* note: must be called under g_deviceslock */
+
+       first = &g_smscore_notifyees;
+
+       for (next = first->next; next != first; next = next->next) {
+               rc = ((struct smscore_device_notifyee_t *) next)->
+                        hotplug(coredev, device, arrival);
+               if (rc < 0)
+                       break;
+       }
+
+       return rc;
+}
+
+static struct smscore_buffer_t *smscore_createbuffer(u8 *buffer,
+               void *common_buffer, dma_addr_t common_buffer_phys) {
+       struct smscore_buffer_t *cb = kmalloc(sizeof(struct smscore_buffer_t),
+                       GFP_KERNEL);
+       if (!cb) {
+               sms_info("kmalloc(...) failed");
+               return NULL;
+       }
+
+       cb->p = buffer;
+       cb->offset_in_common = buffer - (u8 *) common_buffer;
+       cb->phys = common_buffer_phys + cb->offset_in_common;
+
+       return cb;
+}
+
+/**
+ * creates coredev object for a device, prepares buffers,
+ * creates buffer mappings, notifies registered hotplugs about new device.
+ *
+ * @param params device pointer to struct with device specific parameters
+ *               and handlers
+ * @param coredev pointer to a value that receives created coredev object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_device(struct smsdevice_params_t *params,
+               struct smscore_device_t **coredev) {
+       struct smscore_device_t *dev;
+       u8 *buffer;
+
+       sms_info(" entering....smscore_register_device \n");
+       dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
+       if (!dev) {
+               sms_info("kzalloc(...) failed");
+               return -ENOMEM;
+       }
+
+       /* init list entry so it could be safe in smscore_unregister_device */
+       INIT_LIST_HEAD(&dev->entry);
+
+       /* init queues */
+       INIT_LIST_HEAD(&dev->clients);
+       INIT_LIST_HEAD(&dev->buffers);
+
+       /* init locks */
+       spin_lock_init(&dev->clientslock);
+       spin_lock_init(&dev->bufferslock);
+
+       /* init completion events */
+       init_completion(&dev->version_ex_done);
+       init_completion(&dev->data_download_done);
+       init_completion(&dev->trigger_done);
+       init_completion(&dev->init_device_done);
+       init_completion(&dev->reload_start_done);
+       init_completion(&dev->resume_done);
+       init_completion(&dev->gpio_configuration_done);
+       init_completion(&dev->gpio_set_level_done);
+       init_completion(&dev->gpio_get_level_done);
+    // for loopback test
+    init_completion(&dev->loopback_res_done);
+       init_waitqueue_head(&dev->buffer_mng_waitq);
+
+       /* alloc common buffer */
+       sms_info(" entering...alloc common buffer \n");
+       dev->common_buffer_size = params->buffer_size * params->num_buffers;
+#if 0    
+    dev->common_buffer = kmalloc(dev->common_buffer_size, GFP_KERNEL|GFP_DMA);
+    dev->common_buffer_phys =  __pa(dev->common_buffer);
+    sms_debug("dev->common_buffer_phys=0x%x",dev->common_buffer_phys);
+#else
+       dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
+                       &dev->common_buffer_phys, GFP_KERNEL | GFP_DMA);
+#endif
+
+       if (!dev->common_buffer) {
+               smscore_unregister_device(dev);
+               return -ENOMEM;
+       }
+
+
+       /* prepare dma buffers */
+       sms_info(" entering...prepare dma buffers \n");
+
+
+       for (buffer = dev->common_buffer ; dev->num_buffers <
+                       params->num_buffers ; dev->num_buffers++, buffer
+                       += params->buffer_size) {
+               struct smscore_buffer_t *cb = smscore_createbuffer(buffer,
+                               dev->common_buffer, dev->common_buffer_phys);
+               if (!cb) {
+                       smscore_unregister_device(dev);
+                       return -ENOMEM;
+               }
+
+               smscore_putbuffer(dev, cb);
+       }
+
+       sms_info("allocated %d buffers", dev->num_buffers);
+
+       dev->mode = DEVICE_MODE_NONE;
+       dev->context = params->context;
+       dev->device = params->device;
+       dev->setmode_handler = params->setmode_handler;
+       dev->detectmode_handler = params->detectmode_handler;
+       dev->sendrequest_handler = params->sendrequest_handler;
+       dev->preload_handler = params->preload_handler;
+       dev->postload_handler = params->postload_handler;
+
+       dev->device_flags = params->flags;
+       strcpy(dev->devpath, params->devpath);
+
+       smscore_registry_settype(dev->devpath, params->device_type);
+
+       /* add device to devices list */
+       kmutex_lock(&g_smscore_deviceslock);
+       list_add(&dev->entry, &g_smscore_devices);
+       kmutex_unlock(&g_smscore_deviceslock);
+
+       *coredev = dev;
+        panic_core_dev = dev ;
+       sms_info("device %p created", dev);
+
+       return 0;
+}
+
+/**
+ * sets initial device mode and notifies client hotplugs that device is ready
+ *
+ * @param coredev pointer to a coredev object returned by
+ *               smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_start_device(struct smscore_device_t *coredev)
+{
+       int rc;
+
+#ifdef REQUEST_FIRMWARE_SUPPORTED
+       rc = smscore_set_device_mode(coredev, smscore_registry_getmode(
+                       coredev->devpath));
+       if (rc < 0) {
+               sms_info("set device mode faile , rc %d", rc);
+               return rc;
+       }
+#endif
+
+       kmutex_lock(&g_smscore_deviceslock);
+
+       rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+
+       sms_info("device %p started, rc %d", coredev, rc);
+
+       kmutex_unlock(&g_smscore_deviceslock);
+
+       return rc;
+}
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+               void *buffer, size_t size, struct completion *completion) {
+       int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+       if (rc < 0) {
+               sms_info("sendrequest returned error %d", rc);
+               return rc;
+       }
+
+       return wait_for_completion_timeout(completion,
+                       msecs_to_jiffies(10000)) ? 0 : -ETIME;//10000
+}
+
+static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
+               void *buffer, size_t size) {
+       struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
+       struct SmsMsgHdr_ST *msg;
+       u32 mem_address;
+       u8 *payload = firmware->Payload;
+       int rc = 0;
+
+       int index = 0;
+
+       firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
+       firmware->Length = le32_to_cpu(firmware->Length);
+
+       mem_address = firmware->StartAddress;
+    
+    sms_info("loading FW to addr 0x%x size %d",
+            mem_address, firmware->Length);
+    if (coredev->preload_handler) {
+        rc = coredev->preload_handler(coredev->context);
+        if (rc < 0)
+       {
+           sms_err("sms preload handler fail !!!");     
+          return rc;
+       }
+    }
+
+    sms_info("preload handle after");
+
+
+       /* PAGE_SIZE buffer shall be enough and dma aligned */
+       msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+       if (!msg)
+               return -ENOMEM;
+    #if 1
+   // while (index < 300)//hzb test 0527
+    {
+       index++;
+
+       //if (coredev->mode != DEVICE_MODE_NONE) //hzb test 0527
+       {
+               sms_info("sending MSG_SMS_GET_VERSION_EX_REQ command.");
+               SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
+                               sizeof(struct SmsMsgHdr_ST));
+               smsendian_handle_tx_message((struct SmsMsgHdr_ST *)msg);
+               rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
+                               &coredev->version_ex_done);
+    //         mem_address = *(u32 *) &payload[20];
+               sms_info("sms get version req ret=0x%x",rc);
+               mdelay(5);
+       }
+    }//hzb test 0527
+#endif
+
+    #if 1
+       while (size && rc >= 0) {
+               struct SmsDataDownload_ST *DataMsg =
+                               (struct SmsDataDownload_ST *) msg;
+               int payload_size = min((int)size, SMS_MAX_PAYLOAD_SIZE);
+
+               SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
+                               (u16) (sizeof(struct SmsMsgHdr_ST) +
+                                               sizeof(u32) + payload_size));
+
+               DataMsg->MemAddr = mem_address;
+               memcpy(DataMsg->Payload, payload, payload_size);
+
+               smsendian_handle_tx_message((struct SmsMsgHdr_ST *)msg);
+               if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
+                               (coredev->mode  == DEVICE_MODE_NONE))
+                       rc = coredev->sendrequest_handler(coredev->context,DataMsg,DataMsg->xMsgHeader.msgLength);
+               else
+                       rc = smscore_sendrequest_and_wait(coredev, DataMsg,DataMsg->xMsgHeader.msgLength,&coredev->data_download_done);
+
+               payload += payload_size;
+               size -= payload_size;
+               mem_address += payload_size;
+       }
+
+       if (rc >= 0) {
+               if (coredev->mode == DEVICE_MODE_NONE) {
+                       struct SmsMsgData_ST *TriggerMsg =
+                                       (struct SmsMsgData_ST *) msg;
+
+                       SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
+                                       sizeof(struct SmsMsgHdr_ST) +
+                                       sizeof(u32) * 5);
+
+                       TriggerMsg->msgData[0] = firmware->StartAddress;
+                       /* Entry point */
+                       TriggerMsg->msgData[1] = 5; /* Priority */
+                       TriggerMsg->msgData[2] = 0x200; /* Stack size */
+                       TriggerMsg->msgData[3] = 0; /* Parameter */
+                       TriggerMsg->msgData[4] = 4; /* Task ID */
+
+                       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)msg);
+                       if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
+                               rc = coredev->sendrequest_handler(coredev->
+                                       context, TriggerMsg,
+                                       TriggerMsg->xMsgHeader.msgLength);
+                               msleep(100);
+                       } else
+                               rc = smscore_sendrequest_and_wait(coredev,
+                                       TriggerMsg,
+                                       TriggerMsg->xMsgHeader.msgLength,
+                                       &coredev->trigger_done);
+               } else {
+                       SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
+                                       sizeof(struct SmsMsgHdr_ST));
+                       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)msg);
+                       rc = coredev->sendrequest_handler(coredev->context, msg,
+                                       msg->msgLength);
+               }
+               msleep(500);
+       }
+#endif
+       sms_debug("rc=%d, postload=%p ", rc, coredev->postload_handler);
+
+       kfree(msg);
+
+       return ((rc >= 0) && coredev->postload_handler) ?
+                       coredev->postload_handler(coredev->context) : rc;
+}
+
+/**
+ * loads specified firmware into a buffer and calls device loadfirmware_handler
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param filename null-terminated string specifies firmware file name
+ * @param loadfirmware_handler device handler that loads firmware
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
+               char *filename, loadfirmware_t loadfirmware_handler) {
+       int rc = -ENOENT;
+       u8 *fw_buf;
+       u32 fw_buf_size;
+
+#ifdef REQUEST_FIRMWARE_SUPPORTED
+       const struct firmware *fw;
+
+       if (loadfirmware_handler == NULL && !(coredev->device_flags
+                       & SMS_DEVICE_FAMILY2))
+               return -EINVAL;
+
+       rc = request_firmware(&fw, filename, coredev->device);
+       if (rc < 0) {
+               sms_info("failed to open \"%s\"", filename);
+               return rc;
+       }
+       sms_info("read FW %s, size=%zd", filename, fw->size);
+       fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
+                               GFP_KERNEL | GFP_DMA);
+       if (!fw_buf) {
+               sms_info("failed to allocate firmware buffer");
+               return -ENOMEM;
+       }
+       memcpy(fw_buf, fw->data, fw->size);
+       fw_buf_size = fw->size;
+#else
+       if (!coredev->fw_buf) {
+               sms_info("missing fw file buffer");
+               return -EINVAL;
+       }
+       fw_buf = coredev->fw_buf;
+       fw_buf_size = coredev->fw_buf_size;
+#endif
+       rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+               smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
+               : /*loadfirmware_handler(coredev->context, fw_buf,
+               fw_buf_size);*/printk(" error - should not be here\n");
+       kfree(fw_buf);
+
+#ifdef REQUEST_FIRMWARE_SUPPORTED
+       release_firmware(fw);
+#else
+       coredev->fw_buf = NULL;
+       coredev->fw_buf_size = 0;
+#endif
+       return rc;
+}
+
+/**
+ * notifies all clients registered with the device, notifies hotplugs,
+ * frees all buffers and coredev object
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+void smscore_unregister_device(struct smscore_device_t *coredev)
+{
+       struct smscore_buffer_t *cb;
+       int num_buffers = 0;
+       int retry = 0;
+
+       kmutex_lock(&g_smscore_deviceslock);
+
+       smscore_notify_clients(coredev);
+       smscore_notify_callbacks(coredev, NULL, 0);
+
+       /* at this point all buffers should be back
+        * onresponse must no longer be called */
+
+       while (1) {
+               while(!list_empty(&coredev->buffers))
+               {
+                       cb = (struct smscore_buffer_t *) coredev->buffers.next;
+                       list_del(&cb->entry);
+                       kfree(cb);
+                       num_buffers++;
+               }
+               if (num_buffers == coredev->num_buffers ) 
+                       break;
+               if (++retry > 10) {
+                       sms_info("exiting although "
+                                       "not all buffers released.");
+                       break;
+               }
+
+               sms_info("waiting for %d buffer(s)",
+                               coredev->num_buffers - num_buffers);
+               msleep(100);
+       }
+
+       sms_info("freed %d buffers", num_buffers);
+
+    if(coredev->common_buffer)
+    {
+#if 0   //spi kmalloc
+        kfree(coredev->common_buffer);
+#else
+               dma_free_coherent(NULL, coredev->common_buffer_size,coredev->common_buffer, coredev->common_buffer_phys); 
+#endif                 
+    }
+       if (coredev->fw_buf != NULL)
+               kfree(coredev->fw_buf);
+        
+       list_del(&coredev->entry);
+       kfree(coredev);
+    panic_core_dev = NULL ;
+       kmutex_unlock(&g_smscore_deviceslock);
+
+       sms_info("device %p destroyed", coredev);
+}
+
+static int smscore_detect_mode(struct smscore_device_t *coredev)
+{
+       void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       struct SmsMsgHdr_ST *msg =
+                       (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
+       int rc;
+
+       if (!buffer)
+               return -ENOMEM;
+
+       SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
+                       sizeof(struct SmsMsgHdr_ST));
+
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)msg);
+       rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
+                       &coredev->version_ex_done);
+       if (rc == -ETIME) {
+               sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
+
+               if (wait_for_completion_timeout(&coredev->resume_done,
+                               msecs_to_jiffies(5000))) {
+                       rc = smscore_sendrequest_and_wait(coredev, msg,
+                               msg->msgLength, &coredev->version_ex_done);
+                       if (rc < 0)
+                               sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
+                                               "second try, rc %d", rc);
+               } else
+                       rc = -ETIME;
+       }
+
+       kfree(buffer);
+
+       return rc;
+}
+
+static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
+/*Stellar               NOVA A0         Nova B0         VEGA */
+/*DVBT*/
+{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none" },
+/*DVBH*/
+{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none" },
+/*TDMB*/
+{ "none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none" },
+/*DABIP*/{ "none", "none", "none", "none" },
+/*BDA*/
+{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none" },
+/*ISDBT*/
+{ "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none" },
+/*ISDBTBDA*/
+{ "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none" },
+/*CMMB*/{ "none", "none", "none", "cmmb_vega_12mhz.inp" } };
+
+static inline char *sms_get_fw_name(struct smscore_device_t *coredev, int mode,
+               enum sms_device_type_st type) {
+       char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
+       return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
+}
+
+
+int smscore_reset_device_drvs(struct smscore_device_t *coredev)
+
+{
+       int rc = 0;
+       sms_debug("currnet  device mode to %d", coredev->mode);
+               coredev->mode = DEVICE_MODE_NONE;
+               coredev->device_flags =                     SMS_DEVICE_FAMILY2 | SMS_DEVICE_NOT_READY |
+                   SMS_ROM_NO_RESPONSE;
+               
+   return rc;
+}
+
+
+/**
+ * calls device handler to change mode of operation
+ * NOTE: stellar/usb may disconnect when changing mode
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
+{
+       void *buffer;
+       int rc = 0;
+       enum sms_device_type_st type;
+
+
+       sms_info("set device mode to %d", mode);
+    //sms_debug("current device mode, device flags, modes_supported  to %d", coredev->mode, coredev->device_flags, coredev->modes_supported);
+
+       sms_debug("set device mode to %d", mode);
+       if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+               if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
+                       sms_err("invalid mode specified %d", mode);
+                       return -EINVAL;
+               }
+
+               smscore_registry_setmode(coredev->devpath, mode);
+
+               if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
+                       rc = smscore_detect_mode(coredev);
+                       if (rc < 0) {
+                               sms_err("mode detect failed %d", rc);
+                               return rc;
+                       }
+               }
+
+               if (coredev->mode == mode) {
+                       sms_info("device mode %d already set", mode);
+                       return 0;
+               }
+
+               if (!(coredev->modes_supported & (1 << mode))) {
+                       char *fw_filename;
+
+                       type = smscore_registry_gettype(coredev->devpath);
+                       fw_filename = sms_get_fw_name(coredev, mode, type);
+
+                       if(NULL == fw_filename)
+                       {
+                               sms_err("wrong filename");
+                               return rc;
+                       }
+
+                       rc = smscore_load_firmware_from_file(coredev,
+                                       fw_filename, NULL);
+                       if (rc < 0) {
+                               sms_warn("error %d loading firmware: %s, "
+                                       "trying again with default firmware",
+                                       rc, fw_filename);
+
+                               /* try again with the default firmware */
+                               fw_filename = smscore_fw_lkup[mode][type];
+                               rc = smscore_load_firmware_from_file(coredev,
+                                               fw_filename, NULL);
+
+                               if (rc < 0) {
+                                       sms_warn("error %d loading "
+                                                       "firmware: %s", rc,
+                                                       fw_filename);
+                                       return rc;
+                               }
+                       }
+                       sms_info("firmware download success: %s", fw_filename);
+               } else
+               sms_info("mode %d supported by running "
+                                       "firmware", mode);
+
+               buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
+                               SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+               if (buffer) {
+                       struct SmsMsgData_ST *msg =
+                                       (struct SmsMsgData_ST *)
+                                       SMS_ALIGN_ADDRESS(buffer);
+
+                       SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
+                                       sizeof(struct SmsMsgData_ST));
+                       msg->msgData[0] = mode;
+
+                       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)msg);
+                       rc = smscore_sendrequest_and_wait(coredev, msg,
+                                       msg->xMsgHeader.msgLength,
+                                       &coredev->init_device_done);
+
+                       kfree(buffer);
+               } else {
+                       sms_err("Could not allocate buffer for "
+                                       "init device message.");
+                       rc = -ENOMEM;
+               }
+
+               // start to do loopback test
+        // rc = AdrLoopbackTest(coredev);
+               //
+
+       } else {
+               if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+                       sms_err("invalid mode specified %d", mode);
+                       return -EINVAL;
+               }
+
+               smscore_registry_setmode(coredev->devpath, mode);
+
+               if (coredev->detectmode_handler)
+                       coredev->detectmode_handler(coredev->context,
+                                       &coredev->mode);
+
+               if (coredev->mode != mode && coredev->setmode_handler)
+                       rc = coredev->setmode_handler(coredev->context, mode);
+       }
+
+       if (rc >= 0) {
+               sms_err("device is ready");
+               coredev->mode = mode;
+               coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
+       }
+
+       if (rc < 0)
+               sms_err("return error code %d.", rc);
+       return rc;
+}
+
+/**
+ * calls device handler to get fw file name
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param filename pointer to user buffer to fill the file name
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_get_fw_filename(struct smscore_device_t *coredev, int mode,
+               char *filename) {
+       int rc = 0;
+       enum sms_device_type_st type;
+       char tmpname[200];
+
+       type = smscore_registry_gettype(coredev->devpath);
+
+#ifdef REQUEST_FIRMWARE_SUPPORTED
+       /* driver not need file system services */
+       tmpname[0] = '\0';
+#else
+       sprintf(tmpname, "%s/%s", DEFAULT_FW_FILE_PATH,
+                       smscore_fw_lkup[mode][type]);
+#endif
+       if (copy_to_user(filename, tmpname, strlen(tmpname) + 1)) {
+               sms_err("Failed copy file path to user buffer\n");
+               return -EFAULT;
+       }
+       return rc;
+}
+
+/**
+ * calls device handler to keep fw buff for later use
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param ufwbuf  pointer to user fw buffer
+ * @param size    size in bytes of buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_send_fw_file(struct smscore_device_t *coredev, u8 *ufwbuf,
+               int size) {
+       int rc = 0;
+
+       /* free old buffer */
+       if (coredev->fw_buf != NULL) {
+               kfree(coredev->fw_buf);
+               coredev->fw_buf = NULL;
+       }
+
+       coredev->fw_buf = kmalloc(ALIGN(size, SMS_ALLOC_ALIGNMENT), GFP_KERNEL | GFP_DMA);
+       if (!coredev->fw_buf) {
+               sms_err("Failed allocate FW buffer memory\n");
+               return -EFAULT;
+       }
+
+       if (copy_from_user(coredev->fw_buf, ufwbuf, size)) {
+               sms_err("Failed copy FW from user buffer\n");
+               kfree(coredev->fw_buf);
+               return -EFAULT;
+       }
+       coredev->fw_buf_size = size;
+
+       return rc;
+}
+
+/**
+ * calls device handler to get current mode of operation
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return current mode
+ */
+int smscore_get_device_mode(struct smscore_device_t *coredev)
+{
+       return coredev->mode;
+}
+
+/**
+ * find client by response id & type within the clients list.
+ * return client handle or NULL.
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param data_type client data type (SMS_DONT_CARE for all types)
+ * @param id client id (SMS_DONT_CARE for all id)
+ *
+ */
+static struct smscore_client_t *smscore_find_client(
+               struct smscore_device_t *coredev, int data_type, int id) {
+       struct smscore_client_t *client = NULL;
+       struct list_head *next, *first;
+       unsigned long flags;
+       struct list_head *firstid, *nextid;
+
+       spin_lock_irqsave(&coredev->clientslock, flags);
+       first = &coredev->clients;
+       for (next = first->next; (next != first) && !client;
+                       next = next->next) {
+               firstid = &((struct smscore_client_t *) next)->idlist;
+               for (nextid = firstid->next; nextid != firstid;
+                               nextid = nextid->next) {
+                       if ((((struct smscore_idlist_t *) nextid)->id == id)
+                                       && (((struct smscore_idlist_t *)
+                                                nextid)->data_type
+                                               == data_type
+                                               || (((struct smscore_idlist_t *)
+                                               nextid)->data_type == 0))) {
+                               client = (struct smscore_client_t *) next;
+                               break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&coredev->clientslock, flags);
+       return client;
+}
+
+/**
+ * find client by response id/type, call clients onresponse handler
+ * return buffer to pool on error
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param cb pointer to response buffer descriptor
+ *
+ */
+void smscore_onresponse(struct smscore_device_t *coredev,
+               struct smscore_buffer_t *cb) {
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
+                       + cb->offset);
+       struct smscore_client_t *client = smscore_find_client(coredev,
+                       phdr->msgType, phdr->msgDstId);
+       int rc = -EBUSY;
+
+       static unsigned long last_sample_time; /* = 0; */
+       static int data_total; /* = 0; */
+       unsigned long time_now = jiffies_to_msecs(jiffies);
+
+
+//for test , print the version , zyc
+       if(0)
+       {
+               struct SmsVersionRes_ST *vers = (struct SmsVersionRes_ST *)phdr;
+
+               if(phdr->msgType == MSG_SMS_GET_VERSION_EX_RES)
+               {
+                       smsendian_handle_rx_message((struct SmsMsgData_ST *)phdr);
+               
+               
+                       //struct SmsVersionRes_ST *ver = (struct SmsVersionRes_ST *) phdr;
+            
+                       sms_debug("MSG_SMS_GET_VERSION_EX_RES "
+                                       "id %d prots 0x%x ver %d.%d\n",
+                                       vers->FirmwareId,
+                                       vers->SupportedProtocols,
+                                       vers->RomVersionMajor,
+                                       vers->RomVersionMinor);
+               }
+
+               
+       }
+
+       if (!last_sample_time)
+               last_sample_time = time_now;
+
+       if (time_now - last_sample_time > 10000) {
+               sms_debug("\ndata rate %d bytes/secs",
+                               (int)((data_total * 1000) /
+                                               (time_now - last_sample_time)));
+
+               last_sample_time = time_now;
+               data_total = 0;
+       }
+        
+  
+       data_total += cb->size;
+       /* If no client registered for type & id,
+        * check for control client where type is not registered */
+        
+       if (client)
+       {
+               //sms_debug("client=0x %x\n", client);
+               rc = client->onresponse_handler(client->context, cb);
+       }       
+       sms_debug("onresponse_handler ret = 0x%x\n", rc);
+        sms_debug("phdr->msgType %d\n", phdr->msgType);
+
+
+
+       if (rc < 0) {
+               smsendian_handle_rx_message((struct SmsMsgData_ST *)phdr);
+
+               switch (phdr->msgType) {
+               case MSG_SMS_GET_VERSION_EX_RES: {
+                       struct SmsVersionRes_ST *ver = (struct SmsVersionRes_ST *)phdr;
+            
+                       sms_debug("MSG_SMS_GET_VERSION_EX_RES "
+                                       "id %d prots 0x%x ver %d.%d",
+                                       ver->FirmwareId,
+                                       ver->SupportedProtocols,
+                                       ver->RomVersionMajor,
+                                       ver->RomVersionMinor);
+
+                       coredev->mode = ver->FirmwareId == 255 ? DEVICE_MODE_NONE : ver->FirmwareId;
+                       coredev->modes_supported = ver->SupportedProtocols;
+
+                       complete(&coredev->version_ex_done);
+                       break;
+               }
+               case MSG_SMS_INIT_DEVICE_RES:
+                       sms_debug("MSG_SMS_INIT_DEVICE_RES");
+                       complete(&coredev->init_device_done);
+                       break;
+               case MSG_SW_RELOAD_START_RES:
+                       sms_debug("MSG_SW_RELOAD_START_RES");
+                       complete(&coredev->reload_start_done);
+                       break;
+               case MSG_SMS_DATA_DOWNLOAD_RES:
+                       complete(&coredev->data_download_done);
+                       break;
+               case MSG_SW_RELOAD_EXEC_RES:
+                       sms_debug("MSG_SW_RELOAD_EXEC_RES");
+                       break;
+               case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
+                       sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
+                       complete(&coredev->trigger_done);
+                       break;
+               case MSG_SMS_SLEEP_RESUME_COMP_IND:
+                       complete(&coredev->resume_done);
+                       break;
+               case MSG_SMS_GPIO_CONFIG_EX_RES:
+                       sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
+                       complete(&coredev->gpio_configuration_done);
+                       break;
+               case MSG_SMS_GPIO_SET_LEVEL_RES:
+                       sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
+                       complete(&coredev->gpio_set_level_done);
+                       break;
+               case MSG_SMS_GPIO_GET_LEVEL_RES:
+               {
+                       u32 *msgdata = (u32 *) phdr;
+                       coredev->gpio_get_res = msgdata[1];
+                       sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", coredev->gpio_get_res);
+                       complete(&coredev->gpio_get_level_done);
+                       break;
+               }
+
+// loopback in the drv
+
+               case MSG_SMS_LOOPBACK_RES:
+               {
+                   //u32 *msgdata = (u32 *) phdr;
+                       memcpy( g_LbResBuf, (u8 *)phdr, phdr->msgLength );
+                       sms_debug("MSG_SMS_LOOPBACK_RES \n");
+                       complete(&coredev->loopback_res_done);
+                       break;
+               }
+
+               default:
+#if 0
+                       sms_info("no client (%p) or error (%d), "
+                                       "type:%d dstid:%d", client, rc,
+                                       phdr->msgType, phdr->msgDstId);
+#endif
+                       break;
+               }
+
+               smscore_putbuffer(coredev, cb);
+               //sms_debug("after putbuffer \n");
+
+               
+       }
+}
+
+/**
+ * return pointer to next free buffer descriptor from core pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return pointer to descriptor on success, NULL on error.
+ */
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+       struct smscore_buffer_t *cb = NULL;
+       unsigned long flags;
+
+       DEFINE_WAIT(wait);
+
+       spin_lock_irqsave(&coredev->bufferslock, flags);
+
+       /* This function must return a valid buffer, since the buffer list is
+        * finite, we check that there is an available buffer, if not, we wait
+        * until such buffer become available.
+        */
+
+       prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
+
+       if (list_empty(&coredev->buffers))
+       {
+        //to avoid rx buffers hung
+        printk("eladr: smscore_getbuffer scheduled caus list is empty\n");
+        spin_unlock_irqrestore(&coredev->bufferslock, flags);
+        schedule();
+        spin_lock_irqsave(&coredev->bufferslock, flags);
+       }
+
+    //printk("smscore_getbuffer call finish_wait\n");
+       finish_wait(&coredev->buffer_mng_waitq, &wait);
+
+// if list is still empty we will return null
+       if (list_empty(&coredev->buffers))
+       {
+               //buffer is null
+               printk("eladr: smscore_getbuffer fail to allocate buffer, returning null \n");          
+       }
+       else
+       {
+               cb = (struct smscore_buffer_t *) coredev->buffers.next;
+               if(cb->entry.prev==LIST_POISON1 || cb->entry.next==LIST_POISON1 || cb->entry.prev==LIST_POISON2 || cb->entry.next==LIST_POISON2 )
+               {
+                       printk("smscore_getbuffer list is no good\n");  
+                       spin_unlock_irqrestore(&coredev->bufferslock, flags); 
+                       return NULL;
+               }
+
+        //printk("smscore_getbuffer buffer was allocated cb=0x%x\n", cb);
+               list_del(&cb->entry);
+       }
+
+       spin_unlock_irqrestore(&coredev->bufferslock, flags);
+
+       return cb;
+}
+
+/**
+ * return buffer descriptor to a pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param cb pointer buffer descriptor
+ *
+ */
+void smscore_putbuffer(struct smscore_device_t *coredev,
+    struct smscore_buffer_t *cb) {
+    wake_up_interruptible(&coredev->buffer_mng_waitq);
+    list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
+}
+
+static int smscore_validate_client(struct smscore_device_t *coredev,
+               struct smscore_client_t *client, int data_type, int id) {
+       struct smscore_idlist_t *listentry;
+       struct smscore_client_t *registered_client;
+
+       if (!client) {
+               sms_err("bad parameter.");
+               return -EFAULT;
+       }
+       registered_client = smscore_find_client(coredev, data_type, id);
+       if (registered_client == client)
+               return 0;
+
+       if (registered_client) {
+               sms_err("The msg ID already registered to another client.");
+               return -EEXIST;
+       }
+       listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
+       if (!listentry) {
+               sms_err("Can't allocate memory for client id.");
+               return -ENOMEM;
+       }
+       listentry->id = id;
+       listentry->data_type = data_type;
+       list_add_locked(&listentry->entry, &client->idlist,
+                       &coredev->clientslock);
+       return 0;
+}
+
+/**
+ * creates smsclient object, check that id is taken by another client
+ *
+ * @param coredev pointer to a coredev object from clients hotplug
+ * @param initial_id all messages with this id would be sent to this client
+ * @param data_type all messages of this type would be sent to this client
+ * @param onresponse_handler client handler that is called to
+ *                           process incoming messages
+ * @param onremove_handler client handler that is called when device is removed
+ * @param context client-specific context
+ * @param client pointer to a value that receives created smsclient object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_client(struct smscore_device_t *coredev,
+               struct smsclient_params_t *params,
+                               struct smscore_client_t **client) {
+       struct smscore_client_t *newclient;
+    
+       /* check that no other channel with same parameters exists */
+    
+       sms_info("entering....smscore_register_client \n");
+
+       if (smscore_find_client(coredev, params->data_type,     params->initial_id)) {
+               sms_err("Client already exist.");
+               return -EEXIST;
+       }
+
+       newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
+       if (!newclient) {
+               sms_err("Failed to allocate memory for client.");
+               return -ENOMEM;
+       }
+
+       INIT_LIST_HEAD(&newclient->idlist);
+       newclient->coredev = coredev;
+       newclient->onresponse_handler = params->onresponse_handler;
+       newclient->onremove_handler = params->onremove_handler;
+       newclient->context = params->context;
+       list_add_locked(&newclient->entry, &coredev->clients,&coredev->clientslock);
+       smscore_validate_client(coredev, newclient, params->data_type,params->initial_id);
+       *client = newclient;
+       sms_debug("Register new client %p DT=%d ID=%d",
+               params->context, params->data_type, params->initial_id);
+
+       return 0;
+}
+
+/**
+ * frees smsclient object and all subclients associated with it
+ *
+ * @param client pointer to smsclient object returned by
+ *               smscore_register_client
+ *
+ */
+void smscore_unregister_client(struct smscore_client_t *client)
+{
+       struct smscore_device_t *coredev = client->coredev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&coredev->clientslock, flags);
+
+       while (!list_empty(&client->idlist)) {
+               struct smscore_idlist_t *identry =
+                               (struct smscore_idlist_t *) client->idlist.next;
+               list_del(&identry->entry);
+               kfree(identry);
+       }
+
+       sms_info("%p", client->context);
+
+       list_del(&client->entry);
+       kfree(client);
+
+       spin_unlock_irqrestore(&coredev->clientslock, flags);
+}
+
+/**
+ * verifies that source id is not taken by another client,
+ * calls device handler to send requests to the device
+ *
+ * @param client pointer to smsclient object returned by
+ *               smscore_register_client
+ * @param buffer pointer to a request buffer
+ * @param size size (in bytes) of request buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smsclient_sendrequest(struct smscore_client_t *client, void *buffer,
+               size_t size) {
+       struct smscore_device_t *coredev;
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
+       int rc;
+
+       if (client == NULL) {
+               sms_err("Got NULL client");
+               return -EINVAL;
+       }
+
+       coredev = client->coredev;
+
+       /* check that no other channel with same id exists */
+       if (coredev == NULL) {
+               sms_err("Got NULL coredev");
+               return -EINVAL;
+       }
+
+       rc = smscore_validate_client(client->coredev, client, 0,
+                       phdr->msgSrcId);
+       if (rc < 0)
+               return rc;
+
+       return coredev->sendrequest_handler(coredev->context, buffer, size);
+}
+
+#ifdef SMS_HOSTLIB_SUBSYS
+/**
+ * return the size of large (common) buffer
+ *
+ * @param coredev pointer to a coredev object from clients hotplug
+ *
+ * @return size (in bytes) of the buffer
+ */
+int smscore_get_common_buffer_size(struct smscore_device_t *coredev)
+{
+       return coredev->common_buffer_size;
+}
+
+/**
+ * maps common buffer (if supported by platform)
+ *
+ * @param coredev pointer to a coredev object from clients hotplug
+ * @param vma pointer to vma struct from mmap handler
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_map_common_buffer(struct smscore_device_t *coredev,
+               struct vm_area_struct *vma)
+{
+       unsigned long end = vma->vm_end,
+       start = vma->vm_start,
+       size = PAGE_ALIGN(coredev->common_buffer_size);
+
+       if (!(vma->vm_flags & (VM_READ | VM_SHARED)) ||
+                       (vma->vm_flags & VM_WRITE)) {
+               sms_err("invalid vm flags");
+               return -EINVAL;
+       }
+
+       if ((end - start) != size) {
+               sms_err("invalid size %d expected %d",
+                               (int)(end - start), (int)size);
+               return -EINVAL;
+       }
+
+       if (remap_pfn_range(vma, start,
+                       coredev->common_buffer_phys >> PAGE_SHIFT,
+                       size, pgprot_noncached(vma->vm_page_prot))) {
+               sms_err("remap_page_range failed");
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+#endif /* SMS_HOSTLIB_SUBSYS */
+
+static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
+               u32 *pGroupNum, u32 *pGroupCfg) {
+
+       *pGroupCfg = 1;
+
+       if (PinNum >= 0 && PinNum <= 1) {
+               *pTranslatedPinNum = 0;
+               *pGroupNum = 9;
+               *pGroupCfg = 2;
+       } else if (PinNum >= 2 && PinNum <= 6) {
+               *pTranslatedPinNum = 2;
+               *pGroupNum = 0;
+               *pGroupCfg = 2;
+       } else if (PinNum >= 7 && PinNum <= 11) {
+               *pTranslatedPinNum = 7;
+               *pGroupNum = 1;
+       } else if (PinNum >= 12 && PinNum <= 15) {
+               *pTranslatedPinNum = 12;
+               *pGroupNum = 2;
+               *pGroupCfg = 3;
+       } else if (PinNum == 16) {
+               *pTranslatedPinNum = 16;
+               *pGroupNum = 23;
+       } else if (PinNum >= 17 && PinNum <= 24) {
+               *pTranslatedPinNum = 17;
+               *pGroupNum = 3;
+       } else if (PinNum == 25) {
+               *pTranslatedPinNum = 25;
+               *pGroupNum = 6;
+       } else if (PinNum >= 26 && PinNum <= 28) {
+               *pTranslatedPinNum = 26;
+               *pGroupNum = 4;
+       } else if (PinNum == 29) {
+               *pTranslatedPinNum = 29;
+               *pGroupNum = 5;
+               *pGroupCfg = 2;
+       } else if (PinNum == 30) {
+               *pTranslatedPinNum = 30;
+               *pGroupNum = 8;
+       } else if (PinNum == 31) {
+               *pTranslatedPinNum = 31;
+               *pGroupNum = 17;
+       } else
+               return -1;
+
+       *pGroupCfg <<= 24;
+
+       return 0;
+}
+
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+               struct smscore_gpio_config *pGpioConfig) {
+
+       u32 totalLen;
+       u32 TranslatedPinNum;
+       u32 GroupNum;
+       u32 ElectricChar;
+       u32 groupCfg;
+       void *buffer;
+       int rc;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[6];
+       } *pMsg;
+
+
+       if (PinNum > MAX_GPIO_PIN_NUMBER)
+               return -EINVAL;
+
+       if (pGpioConfig == NULL)
+               return -EINVAL;
+
+       totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
+
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
+
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+
+       if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
+               pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
+               if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
+                               &groupCfg) != 0)
+                       return -EINVAL;
+
+               pMsg->msgData[1] = TranslatedPinNum;
+               pMsg->msgData[2] = GroupNum;
+               ElectricChar = (pGpioConfig->PullUpDown)
+                               | (pGpioConfig->InputCharacteristics << 2)
+                               | (pGpioConfig->OutputSlewRate << 3)
+                               | (pGpioConfig->OutputDriving << 4);
+               pMsg->msgData[3] = ElectricChar;
+               pMsg->msgData[4] = pGpioConfig->Direction;
+               pMsg->msgData[5] = groupCfg;
+       } else {
+               pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
+               pMsg->msgData[1] = pGpioConfig->PullUpDown;
+               pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
+               pMsg->msgData[3] = pGpioConfig->OutputDriving;
+               pMsg->msgData[4] = pGpioConfig->Direction;
+               pMsg->msgData[5] = 0;
+       }
+
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_configuration_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_configure timeout");
+               else
+                       sms_err("smscore_gpio_configure error");
+       }
+       kfree(buffer);
+
+       return rc;
+}
+
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 NewLevel) {
+
+       u32 totalLen;
+       int rc;
+       void *buffer;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[3]; /* keep it 3 ! */
+       } *pMsg;
+
+       if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
+                       (PinNum > MAX_GPIO_PIN_NUMBER))
+               return -EINVAL;
+
+       totalLen = sizeof(struct SmsMsgHdr_ST) +
+                       (3 * sizeof(u32)); /* keep it 3 ! */
+
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
+
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+       pMsg->msgData[1] = NewLevel;
+
+       /* Send message to SMS */
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_set_level_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_set_level timeout");
+               else
+                       sms_err("smscore_gpio_set_level error");
+       }
+       kfree(buffer);
+
+       return rc;
+}
+
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 *level) {
+
+       u32 totalLen;
+       int rc;
+       void *buffer;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[2];
+       } *pMsg;
+
+
+       if (PinNum > MAX_GPIO_PIN_NUMBER)
+               return -EINVAL;
+
+       totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
+
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
+
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+       pMsg->msgData[1] = 0;
+
+       /* Send message to SMS */
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_get_level_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_get_level timeout");
+               else
+                       sms_err("smscore_gpio_get_level error");
+       }
+       kfree(buffer);
+
+       /* Its a race between other gpio_get_level() and the copy of the single
+        * global 'coredev->gpio_get_res' to  the function's variable 'level'
+        */
+       *level = coredev->gpio_get_res;
+
+       return rc;
+}
+
+//zyc
+static request_cmmb_gpio(void)
+{
+       int ret;
+       ret = gpio_request(CMMB_1186_POWER_RESET, NULL);
+       if (ret) {
+       printk("%s:failed to request CMMB_1186_POWER_RESET\n",__FUNCTION__);
+       //return ret;
+       }
+
+       ret = gpio_request(CMMB_1186_POWER_DOWN, NULL);
+       if (ret) {
+       printk("%s:failed to request CMMB_1186_POWER_DOWN\n",__FUNCTION__);
+       //return ret;
+       }
+       
+
+       ret = gpio_request(CMMB_1186_POWER_ENABLE, NULL);
+       if (ret) {
+       printk("%s:failed to request CMMB_1186_POWER_ENABLE\n",__FUNCTION__);
+       //return ret;
+       }
+       printk("leave the request_cmmb_gpio\n");
+
+}
+
+static int __init smscore_module_init(void)
+{
+       int rc = 0;
+
+       printk("smsmdtv module init...\n");
+       sms_info("entering... smscore_module_init....\n");
+       INIT_LIST_HEAD(&g_smscore_notifyees);
+       INIT_LIST_HEAD(&g_smscore_devices);
+       kmutex_init(&g_smscore_deviceslock);
+
+       INIT_LIST_HEAD(&g_smscore_registry);
+       kmutex_init(&g_smscore_registrylock);
+
+//request the gpio used by cmmb
+       request_cmmb_gpio();
+       /* Register sub system adapter objects */
+
+#ifdef SMS_NET_SUBSYS
+       /* NET Register */
+       rc = smsnet_register();
+       if (rc) {
+               sms_err("Error registering Siano's network client.\n");
+               goto smsnet_error;
+       }
+#endif
+
+#ifdef SMS_HOSTLIB_SUBSYS
+       /* Char interface Register */
+       rc = smschar_register();
+       if (rc) {
+               sms_err("Error registering Siano's char device client.\n");
+               goto smschar_error;
+       }
+#endif
+
+#ifdef SMS_DVB3_SUBSYS
+       /* DVB v.3 Register */
+       rc = smsdvb_register();
+       if (rc) {
+               sms_err("Error registering DVB client.\n");
+               goto smsdvb_error;
+       }
+#endif
+
+       /* Register interfaces objects */
+
+#ifdef SMS_USB_DRV
+       /* USB Register */
+       rc = smsusb_register();
+       if (rc) {
+               sms_err("Error registering USB bus driver.\n");
+               goto sms_bus_drv_error;
+       }
+#endif
+
+#ifdef SMS_SDIO_DRV
+       /* SDIO Register */
+       rc = smssdio_register();
+       if (rc) {
+               sms_err("Error registering SDIO bus driver.\n");
+               goto sms_bus_drv_error;
+       }
+#endif
+
+
+#ifdef SMS_SPI_ROCKCHIP
+
+    sms_debug(KERN_INFO "smsspi_register\n");
+       rc = smsspi_register();  
+       if (rc) {
+               sms_err("Error registering Intel PXA310 SPI bus driver.\n");
+               goto sms_bus_drv_error;
+       }
+#endif
+
+       return rc;
+
+sms_bus_drv_error:
+#ifdef SMS_DVB3_SUBSYS
+       smsdvb_unregister();
+smsdvb_error:
+#endif
+
+#ifdef SMS_HOSTLIB_SUBSYS
+       smschar_unregister();
+smschar_error:
+#endif
+
+#ifdef SMS_NET_SUBSYS
+       smsnet_unregister();
+smsnet_error:
+#endif
+
+       sms_err("rc %d", rc);
+       printk(KERN_INFO "%s, rc %d\n", __func__, rc);
+
+       return rc;
+}
+
+static void __exit smscore_module_exit(void)
+{
+#ifdef SMS_NET_SUBSYS
+       /* Net Unregister */
+       smsnet_unregister();
+#endif
+
+#ifdef SMS_HOSTLIB_SUBSYS
+       /* Char interface Unregister */
+       smschar_unregister();
+#endif
+
+#ifdef SMS_DVB3_SUBSYS
+       /* DVB v.3 unregister */
+       smsdvb_unregister();
+#endif
+
+       /* Unegister interfaces objects */
+#ifdef SMS_USB_DRV
+       /* USB unregister */
+       smsusb_unregister();
+#endif
+
+#ifdef SMS_SDIO_DRV
+       /* SDIO unegister */
+       smssdio_unregister();
+#endif
+
+#ifdef SMS_SPI_ROCKCHIP
+       /* Intel PXA310 SPI unegister */
+       smsspi_unregister();
+#endif
+
+       kmutex_lock(&g_smscore_deviceslock);
+       while (!list_empty(&g_smscore_notifyees)) {
+               struct smscore_device_notifyee_t *notifyee =
+               (struct smscore_device_notifyee_t *)
+               g_smscore_notifyees.next;
+
+               list_del(&notifyee->entry);
+               kfree(notifyee);
+       }
+       kmutex_unlock(&g_smscore_deviceslock);
+
+       kmutex_lock(&g_smscore_registrylock);
+       while (!list_empty(&g_smscore_registry)) {
+               struct smscore_registry_entry_t *entry =
+               (struct smscore_registry_entry_t *)
+               g_smscore_registry.next;
+
+               list_del(&entry->entry);
+               kfree(entry);
+       }
+       kmutex_unlock(&g_smscore_registrylock);
+
+       sms_debug("");
+}
+
+// for loopback test
+// for loopback
+
+int  AdrLoopbackTest( struct smscore_device_t *coredev )
+{
+       char msgbuff[252];
+       struct SmsMsgData_ST* pLoopbackMsg = (struct SmsMsgData_ST*)msgbuff;
+       struct SmsMsgData_ST* pLoopbackRes = (struct SmsMsgData_ST*)g_LbResBuf;
+       int i , j;
+       int g_Loopback_failCounters= 0; 
+       int Len = 252 - sizeof(struct SmsMsgData_ST);
+       char* pPtr;
+       int rc =0;
+
+       pLoopbackMsg->xMsgHeader.msgType = MSG_SMS_LOOPBACK_REQ;
+       pLoopbackMsg->xMsgHeader.msgSrcId = 151;
+       pLoopbackMsg->xMsgHeader.msgDstId = 11;
+       pLoopbackMsg->xMsgHeader.msgFlags = 0;
+       pLoopbackMsg->xMsgHeader.msgLength = 252;
+       
+       sms_info("Loobpack test start.");
+       
+
+       for ( i = 0 ; i < 1000 ; i++ )
+       {
+
+               pPtr = (u8*) &pLoopbackMsg->msgData[1];
+               for ( j = 0 ; j < Len ; j ++ )
+               {
+                       pPtr[j] = i+j;
+               }
+               pLoopbackMsg->msgData[0] = i+1;
+       
+               smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pLoopbackMsg);
+                       rc = smscore_sendrequest_and_wait(coredev, pLoopbackMsg,
+                                       pLoopbackMsg->xMsgHeader.msgLength,
+                                       &coredev->loopback_res_done);
+
+
+               if (rc)
+                       return  rc; 
+
+       
+               pPtr = (u8*) &pLoopbackRes->msgData[1];
+
+               for ( j = 0 ; j < Len ; j ++ )
+               {
+                       if ( pPtr[j] != (u8)(j + i))
+                       {
+                                       sms_err("Loopback data error at byte %u. Exp %u, Got %u", j, (u8)(j+i), pPtr[j] );
+                                       g_Loopback_failCounters++;
+                                       break;
+                       }
+               } //for ( j = 0 ; j < Len ; j ++ )
+       } //for ( i = 0 ; i < 100 ; i++ )
+       sms_info( "Loobpack test end. RUN  times: %d; fail times : %d", i, g_Loopback_failCounters);
+        return rc ;
+}
+
+
+module_init(smscore_module_init);
+module_exit(smscore_module_exit);
+
+MODULE_DESCRIPTION("Siano MDTV Core module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cmmb/siano/smscoreapi.h b/drivers/cmmb/siano/smscoreapi.h
new file mode 100755 (executable)
index 0000000..ba9be1b
--- /dev/null
@@ -0,0 +1,547 @@
+/****************************************************************
+
+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_CORE_API_H__
+#define __SMS_CORE_API_H__
+
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
+#include <asm/page.h>
+#include <linux/mutex.h>
+#include "compat.h"
+
+#ifdef SMS_DVB3_SUBSYS
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#endif
+
+#define kmutex_init(_p_) mutex_init(_p_)
+#define kmutex_lock(_p_) mutex_lock(_p_)
+#define kmutex_trylock(_p_) mutex_trylock(_p_)
+#define kmutex_unlock(_p_) mutex_unlock(_p_)
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define SMS_ALLOC_ALIGNMENT                                    128
+#define SMS_DMA_ALIGNMENT                                      16
+#define SMS_ALIGN_ADDRESS(addr) \
+       ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
+
+#define SMS_DEVICE_FAMILY2                                     1
+#define SMS_ROM_NO_RESPONSE                                    2
+#define SMS_DEVICE_NOT_READY                                   0x8000000
+
+enum sms_device_type_st {
+       SMS_STELLAR = 0,
+       SMS_NOVA_A0,
+       SMS_NOVA_B0,
+       SMS_VEGA,
+       SMS_NUM_OF_DEVICE_TYPES
+};
+
+struct smscore_device_t;
+struct smscore_client_t;
+struct smscore_buffer_t;
+
+typedef int (*hotplug_t) (struct smscore_device_t *coredev,
+                         struct device *device, int arrival);
+
+typedef int (*setmode_t) (void *context, int mode);
+typedef void (*detectmode_t) (void *context, int *mode);
+typedef int (*sendrequest_t) (void *context, void *buffer, size_t size);
+typedef int (*loadfirmware_t) (void *context, void *buffer, size_t size);
+typedef int (*preload_t) (void *context);
+typedef int (*postload_t) (void *context);
+
+typedef int (*onresponse_t) (void *context, struct smscore_buffer_t *cb);
+typedef void (*onremove_t) (void *context);
+
+struct smscore_buffer_t {
+       /* public members, once passed to clients can be changed freely */
+       struct list_head entry;
+       int size;
+       int offset;
+
+       /* private members, read-only for clients */
+       void *p;
+       dma_addr_t phys;
+       unsigned long offset_in_common;
+};
+
+struct smsdevice_params_t {
+       struct device *device;
+
+       int buffer_size;
+       int num_buffers;
+
+       char devpath[32];
+       unsigned long flags;
+
+       setmode_t setmode_handler;
+       detectmode_t detectmode_handler;
+       sendrequest_t sendrequest_handler;
+       preload_t preload_handler;
+       postload_t postload_handler;
+
+       void *context;
+       enum sms_device_type_st device_type;
+};
+
+struct smsclient_params_t {
+       int initial_id;
+       int data_type;
+       onresponse_t onresponse_handler;
+       onremove_t onremove_handler;
+
+       void *context;
+};
+
+/* GPIO definitions for antenna frequency domain control (SMS8021) */
+#define SMS_ANTENNA_GPIO_0                             1
+#define SMS_ANTENNA_GPIO_1                             0
+
+#define BW_8_MHZ                                       0
+#define BW_7_MHZ                                       1
+#define BW_6_MHZ                                       2
+#define BW_5_MHZ                                       3
+#define BW_ISDBT_1SEG                                  4
+#define BW_ISDBT_3SEG                                  5
+
+#define MSG_HDR_FLAG_SPLIT_MSG                         4
+
+#define MAX_GPIO_PIN_NUMBER                            31
+
+#define HIF_TASK                                       11
+#define SMS_HOST_LIB                                   150
+#define DVBT_BDA_CONTROL_MSG_ID                                201
+
+#define SMS_MAX_PAYLOAD_SIZE                           240
+#define SMS_TUNE_TIMEOUT                               500
+
+#define MSG_SMS_GPIO_CONFIG_REQ                                507
+#define MSG_SMS_GPIO_CONFIG_RES                                508
+#define MSG_SMS_GPIO_SET_LEVEL_REQ                     509
+#define MSG_SMS_GPIO_SET_LEVEL_RES                     510
+#define MSG_SMS_GPIO_GET_LEVEL_REQ                     511
+#define MSG_SMS_GPIO_GET_LEVEL_RES                     512
+#define MSG_SMS_RF_TUNE_REQ                            561
+#define MSG_SMS_RF_TUNE_RES                            562
+#define MSG_SMS_INIT_DEVICE_REQ                                578
+#define MSG_SMS_INIT_DEVICE_RES                                579
+#define MSG_SMS_ADD_PID_FILTER_REQ                     601
+#define MSG_SMS_ADD_PID_FILTER_RES                     602
+#define MSG_SMS_REMOVE_PID_FILTER_REQ                  603
+#define MSG_SMS_REMOVE_PID_FILTER_RES                  604
+#define MSG_SMS_DAB_CHANNEL                            607
+#define MSG_SMS_GET_PID_FILTER_LIST_REQ                        608
+#define MSG_SMS_GET_PID_FILTER_LIST_RES                        609
+#define MSG_SMS_GET_STATISTICS_REQ                     615
+#define MSG_SMS_GET_STATISTICS_RES                     616
+#define MSG_SMS_SET_ANTENNA_CONFIG_REQ                 651
+#define MSG_SMS_SET_ANTENNA_CONFIG_RES                 652
+#define MSG_SMS_GET_STATISTICS_EX_REQ                  653
+#define MSG_SMS_GET_STATISTICS_EX_RES                  654
+#define MSG_SMS_SLEEP_RESUME_COMP_IND                  655
+
+#define MSG_SMS_SET_PERIODIC_STATS_REQ     658
+#define MSG_SMS_SET_PERIODIC_STATS_RES     659
+
+#define MSG_SMS_DATA_DOWNLOAD_REQ                      660
+#define MSG_SMS_DATA_DOWNLOAD_RES                      661
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ                 664
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES                 665
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ                        666
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES                        667
+#define MSG_SMS_GET_VERSION_EX_REQ                     668
+#define MSG_SMS_GET_VERSION_EX_RES                     669
+#define MSG_SMS_SET_CLOCK_OUTPUT_REQ                   670
+#define MSG_SMS_I2C_SET_FREQ_REQ                       685
+#define MSG_SMS_GENERIC_I2C_REQ                                687
+#define MSG_SMS_GENERIC_I2C_RES                                688
+#define MSG_SMS_DVBT_BDA_DATA                          693
+#define MSG_SW_RELOAD_REQ                              697
+#define MSG_SMS_DATA_MSG                               699
+#define MSG_SW_RELOAD_START_REQ                                702
+#define MSG_SW_RELOAD_START_RES                                703
+#define MSG_SW_RELOAD_EXEC_REQ                         704
+#define MSG_SW_RELOAD_EXEC_RES                         705
+#define MSG_SMS_SPI_INT_LINE_SET_REQ           710
+#define MSG_SMS_GPIO_CONFIG_EX_REQ                     712
+#define MSG_SMS_GPIO_CONFIG_EX_RES                     713
+#define MSG_SMS_ISDBT_TUNE_REQ                         776
+#define MSG_SMS_ISDBT_TUNE_RES                         777
+
+#define MSG_SMS_LOOPBACK_REQ                           718
+#define MSG_SMS_LOOPBACK_RES                           719
+
+
+#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
+       (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
+       (ptr)->msgLength = len; (ptr)->msgFlags = 0; \
+} while (0)
+#define SMS_INIT_MSG(ptr, type, len) \
+       SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
+
+enum SMS_DVB3_EVENTS {
+       DVB3_EVENT_INIT = 0,
+       DVB3_EVENT_SLEEP,
+       DVB3_EVENT_HOTPLUG,
+       DVB3_EVENT_FE_LOCK,
+       DVB3_EVENT_FE_UNLOCK,
+       DVB3_EVENT_UNC_OK,
+       DVB3_EVENT_UNC_ERR
+};
+
+enum SMS_DEVICE_MODE {
+       DEVICE_MODE_NONE = -1,
+       DEVICE_MODE_DVBT = 0,
+       DEVICE_MODE_DVBH,
+       DEVICE_MODE_DAB_TDMB,
+       DEVICE_MODE_DAB_TDMB_DABIP,
+       DEVICE_MODE_DVBT_BDA,
+       DEVICE_MODE_ISDBT,
+       DEVICE_MODE_ISDBT_BDA,
+       DEVICE_MODE_CMMB,
+       DEVICE_MODE_RAW_TUNER,
+       DEVICE_MODE_MAX,
+};
+
+struct SmsMsgHdr_ST {
+       u16 msgType;
+       u8 msgSrcId;
+       u8 msgDstId;
+       u16 msgLength;          /* Length of entire message, including header */
+       u16 msgFlags;
+};
+
+struct SmsMsgData_ST {
+       struct SmsMsgHdr_ST xMsgHeader;
+       u32 msgData[1];
+};
+
+struct SmsDataDownload_ST {
+       struct SmsMsgHdr_ST xMsgHeader;
+       u32 MemAddr;
+       u8 Payload[SMS_MAX_PAYLOAD_SIZE];
+};
+
+struct SmsVersionRes_ST {
+       struct SmsMsgHdr_ST xMsgHeader;
+
+       u16 ChipModel;          /* e.g. 0x1102 for SMS-1102 "Nova" */
+       u8 Step;                /* 0 - Step A */
+       u8 MetalFix;            /* 0 - Metal 0 */
+
+       u8 FirmwareId;          /* 0xFF ROM, otherwise the
+                                * value indicated by
+                                * SMSHOSTLIB_DEVICE_MODES_E */
+       u8 SupportedProtocols;  /* Bitwise OR combination of
+                                * supported protocols */
+
+       u8 VersionMajor;
+       u8 VersionMinor;
+       u8 VersionPatch;
+       u8 VersionFieldPatch;
+
+       u8 RomVersionMajor;
+       u8 RomVersionMinor;
+       u8 RomVersionPatch;
+       u8 RomVersionFieldPatch;
+
+       u8 TextLabel[34];
+};
+
+struct SmsFirmware_ST {
+       u32 CheckSum;
+       u32 Length;
+       u32 StartAddress;
+       u8 Payload[1];
+};
+
+struct SMSHOSTLIB_STATISTICS_ST {
+       u32 Reserved;           /* Reserved */
+
+       /* Common parameters */
+       u32 IsRfLocked;         /* 0 - not locked, 1 - locked */
+       u32 IsDemodLocked;      /* 0 - not locked, 1 - locked */
+       u32 IsExternalLNAOn;    /* 0 - external LNA off, 1 - external LNA on */
+
+       /* Reception quality */
+       s32 SNR;                /* dB */
+       u32 BER;                /* Post Viterbi BER [1E-5] */
+       u32 FIB_CRC;            /* CRC errors percentage, valid only for DAB */
+       u32 TS_PER;             /* Transport stream PER, 0xFFFFFFFF
+                                * indicate N/A, valid only for DVB-T/H */
+       u32 MFER;               /* DVB-H frame error rate in percentage,
+                                * 0xFFFFFFFF indicate N/A, valid
+                                * only for DVB-H */
+       s32 RSSI;               /* dBm */
+       s32 InBandPwr;          /* In band power in dBM */
+       s32 CarrierOffset;      /* Carrier Offset in bin/1024 */
+
+       /* Transmission parameters, valid only for DVB-T/H */
+       u32 Frequency;          /* Frequency in Hz */
+       u32 Bandwidth;          /* Bandwidth in MHz */
+       u32 TransmissionMode;   /* Transmission Mode, for DAB modes 1-4,
+                                * for DVB-T/H FFT mode carriers in Kilos */
+       u32 ModemState;         /* from SMS_DvbModemState_ET */
+       u32 GuardInterval;      /* Guard Interval, 1 divided by value */
+       u32 CodeRate;           /* Code Rate from SMS_DvbModemState_ET */
+       u32 LPCodeRate;         /* Low Priority Code Rate from
+                                * SMS_DvbModemState_ET */
+       u32 Hierarchy;          /* Hierarchy from SMS_Hierarchy_ET */
+       u32 Constellation;      /* Constellation from SMS_Constellation_ET */
+
+       /* Burst parameters, valid only for DVB-H */
+       u32 BurstSize;          /* Current burst size in bytes */
+       u32 BurstDuration;      /* Current burst duration in mSec */
+       u32 BurstCycleTime;     /* Current burst cycle time in mSec */
+       u32 CalculatedBurstCycleTime;   /* Current burst cycle time in mSec,
+                                        * as calculated by demodulator */
+       u32 NumOfRows;          /* Number of rows in MPE table */
+       u32 NumOfPaddCols;      /* Number of padding columns in MPE table */
+       u32 NumOfPunctCols;     /* Number of puncturing columns in MPE table */
+       /* Burst parameters */
+       u32 ErrorTSPackets;     /* Number of erroneous transport-stream
+                                * packets */
+       u32 TotalTSPackets;     /* Total number of transport-stream packets */
+       u32 NumOfValidMpeTlbs;  /* Number of MPE tables which do not include
+                                * errors after MPE RS decoding */
+       u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
+                                * after MPE RS decoding */
+       u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
+                                   * by MPE RS decoding */
+
+       /* Common params */
+       u32 BERErrorCount;      /* Number of errornous SYNC bits. */
+       u32 BERBitCount;        /* Total number of SYNC bits. */
+
+       /* Interface information */
+       u32 SmsToHostTxErrors;  /* Total number of transmission errors. */
+
+       /* DAB/T-DMB */
+       u32 PreBER;             /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+
+       /* DVB-H TPS parameters */
+       u32 CellId;             /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+                                * if set to 0xFFFFFFFF cell_id not
+                                * yet recovered */
+
+};
+
+struct SmsMsgStatisticsInfo_ST {
+       u32 RequestResult;
+
+       struct SMSHOSTLIB_STATISTICS_ST Stat;
+
+       /* Split the calc of the SNR in DAB */
+       u32 Signal;             /* dB */
+       u32 Noise;              /* dB */
+
+};
+
+struct smscore_gpio_config {
+#define SMS_GPIO_DIRECTION_INPUT  0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+       u8 Direction;
+
+#define SMS_GPIO_PULLUPDOWN_NONE     0
+#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
+#define SMS_GPIO_PULLUPDOWN_PULLUP   2
+#define SMS_GPIO_PULLUPDOWN_KEEPER   3
+       u8 PullUpDown;
+
+#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL  0
+#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
+       u8 InputCharacteristics;
+
+#define SMS_GPIO_OUTPUTSLEWRATE_SLOW           0 /* 10xx */
+#define SMS_GPIO_OUTPUTSLEWRATE_FAST           1 /* 10xx */
+
+#define SMS_GPIO_OUTPUTSLEWRATE_0_45_V_NS      0 /* 11xx */
+#define SMS_GPIO_OUTPUTSLEWRATE_0_9_V_NS       1 /* 11xx */
+#define SMS_GPIO_OUTPUTSLEWRATE_1_7_V_NS       2 /* 11xx */
+#define SMS_GPIO_OUTPUTSLEWRATE_3_3_V_NS       3 /* 11xx */
+       u8 OutputSlewRate;
+
+#define SMS_GPIO_OUTPUTDRIVING_S_4mA           0 /* 10xx */
+#define SMS_GPIO_OUTPUTDRIVING_S_8mA           1 /* 10xx */
+#define SMS_GPIO_OUTPUTDRIVING_S_12mA          2 /* 10xx */
+#define SMS_GPIO_OUTPUTDRIVING_S_16mA          3 /* 10xx */
+
+#define SMS_GPIO_OUTPUTDRIVING_1_5mA           0 /* 11xx */
+#define SMS_GPIO_OUTPUTDRIVING_2_8mA           1 /* 11xx */
+#define SMS_GPIO_OUTPUTDRIVING_4mA                     2 /* 11xx */
+#define SMS_GPIO_OUTPUTDRIVING_7mA                     3 /* 11xx */
+#define SMS_GPIO_OUTPUTDRIVING_10mA                    4 /* 11xx */
+#define SMS_GPIO_OUTPUTDRIVING_11mA                    5 /* 11xx */
+#define SMS_GPIO_OUTPUTDRIVING_14mA                    6 /* 11xx */
+#define SMS_GPIO_OUTPUTDRIVING_16mA                    7 /* 11xx */
+       u8 OutputDriving;
+};
+
+#ifdef SMS_DVB3_SUBSYS
+
+struct smsdvb_client_t {
+       struct list_head entry;
+
+       struct smscore_device_t *coredev;
+       struct smscore_client_t *smsclient;
+
+       struct dvb_adapter adapter;
+       struct dvb_demux demux;
+       struct dmxdev dmxdev;
+       struct dvb_frontend frontend;
+
+       fe_status_t             fe_status;
+       int                     fe_ber, fe_snr, fe_unc, fe_signal_strength;
+
+       struct completion tune_done, stat_done;
+
+       /* todo: save freq/band instead whole struct */
+       struct dvb_frontend_parameters fe_params;
+
+};
+#endif /* SMS_DVB3_SUBSYS */
+
+extern void smsspi_poweron(void);
+extern void smsspi_off(void);
+extern void smscore_registry_setmode(char *devpath, int mode);
+extern int smscore_registry_getmode(char *devpath);
+
+extern int smscore_register_hotplug(hotplug_t hotplug);
+extern void smscore_unregister_hotplug(hotplug_t hotplug);
+
+extern int smscore_register_device(struct smsdevice_params_t *params,
+                                  struct smscore_device_t **coredev);
+extern void smscore_unregister_device(struct smscore_device_t *coredev);
+
+extern int smscore_start_device(struct smscore_device_t *coredev);
+extern int smscore_load_firmware(struct smscore_device_t *coredev,
+                                char *filename,
+                                loadfirmware_t loadfirmware_handler);
+extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
+extern int smscore_get_device_mode(struct smscore_device_t *coredev);
+// Peter add on June 18, 2009
+extern int smscore_reset_device_drvs(struct smscore_device_t *coredev);
+extern int smscore_get_fw_filename(struct smscore_device_t *coredev, int mode,
+                                  char *filename);
+extern int smscore_send_fw_file(struct smscore_device_t *coredev, u8 *ufwbuf,
+                               int size);
+
+extern int smscore_register_client(struct smscore_device_t *coredev,
+                                  struct smsclient_params_t *params,
+                                  struct smscore_client_t **client);
+extern void smscore_unregister_client(struct smscore_client_t *client);
+
+extern int smsclient_sendrequest(struct smscore_client_t *client,
+                                void *buffer, size_t size);
+extern void smscore_onresponse(struct smscore_device_t *coredev,
+                              struct smscore_buffer_t *cb);
+
+extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
+extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
+                                    struct vm_area_struct *vma);
+
+extern struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t
+                                                 *coredev);
+extern void smscore_putbuffer(struct smscore_device_t *coredev,
+                             struct smscore_buffer_t *cb);
+
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+               struct smscore_gpio_config *pGpioConfig);
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 NewLevel);
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 *level);
+
+void smscore_set_board_id(struct smscore_device_t *core, int id);
+int smscore_get_board_id(struct smscore_device_t *core);
+
+#ifdef SMS_HOSTLIB_SUBSYS
+extern int smschar_register(void);
+extern void smschar_unregister(void);
+#endif
+
+#ifdef SMS_NET_SUBSYS
+extern int smsnet_register(void);
+extern void smsnet_unregister(void);
+#endif
+
+#ifdef SMS_DVB3_SUBSYS
+extern int smsdvb_register(void);
+extern void smsdvb_unregister(void);
+#endif
+
+#ifdef SMS_USB_DRV
+extern int smsusb_register(void);
+extern void smsusb_unregister(void);
+#endif
+
+#ifdef SMS_SDIO_DRV
+extern int smssdio_register(void);
+extern void smssdio_unregister(void);
+#endif
+
+#ifdef SMS_SPI_ROCKCHIP
+extern int smsspi_register(void);
+extern void smsspi_unregister(void);
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+extern int sms_debug;
+
+#define DBG_INFO 1
+#define DBG_ADV  2
+
+
+#define sms_printk(kern, fmt, arg...) \
+       printk(kern " " fmt "\n", ##arg)  // to save log
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+       if (sms_debug & lvl) \
+               sms_printk(kern, fmt, ##arg); } while (0)
+
+#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
+#define sms_err(fmt, arg...) \
+       sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
+#define sms_warn(fmt, arg...)  sms_printk(KERN_WARNING, fmt, ##arg)
+#define sms_info(fmt, arg...) \
+       dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
+#define sms_debug(fmt, arg...) \
+       dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)//
+
+
+//define the gpio used 
+#define CMMB_1186_SPIIRQ         RK2818_PIN_PA6  //This Pin is SDK Board GPIOPortA_Pin6 
+#define CMMB_1186_POWER_DOWN     FPGA_PIO2_09 
+#define CMMB_1186_POWER_ENABLE   FPGA_PIO4_03
+#define CMMB_1186_POWER_RESET    FPGA_PIO2_06
+#endif /* __SMS_CORE_API_H__ */
diff --git a/drivers/cmmb/siano/smsdbg_prn.h b/drivers/cmmb/siano/smsdbg_prn.h
new file mode 100755 (executable)
index 0000000..71de343
--- /dev/null
@@ -0,0 +1,63 @@
+/****************************************************************
+
+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 */
+// to enable log
+
+
+//ROCK Enbale Interruption
+//#define SPIBUS_DEBUG 1
+
+#undef PDEBUG                  /* undef it, just in case */
+#ifdef SPIBUS_DEBUG
+
+#define PDEBUG(fmt, args...) \
+       printk(KERN_DEBUG " " fmt,## 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 --git a/drivers/cmmb/siano/smsendian.c b/drivers/cmmb/siano/smsendian.c
new file mode 100755 (executable)
index 0000000..d79aa05
--- /dev/null
@@ -0,0 +1,100 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, 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 <asm/byteorder.h>
+
+#include "smsendian.h"
+#include "smscoreapi.h"
+
+void smsendian_handle_tx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+       int i;
+       int msgWords;
+
+       switch (msg->xMsgHeader.msgType) {
+       case MSG_SMS_DATA_DOWNLOAD_REQ:
+       {
+               msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
+               break;
+       }
+
+       default:
+               msgWords = (msg->xMsgHeader.msgLength -
+                               sizeof(struct SmsMsgHdr_ST))/4;
+
+               for (i = 0; i < msgWords; i++)
+                       msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+               break;
+       }
+#endif /* __BIG_ENDIAN */
+}
+
+void smsendian_handle_rx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+       int i;
+       int msgWords;
+
+       switch (msg->xMsgHeader.msgType) {
+       case MSG_SMS_GET_VERSION_EX_RES:
+       {
+               struct SmsVersionRes_ST *ver =
+                       (struct SmsVersionRes_ST *) msg;
+               ver->ChipModel = le16_to_cpu(ver->ChipModel);
+               break;
+       }
+
+       case MSG_SMS_DVBT_BDA_DATA:
+       case MSG_SMS_DAB_CHANNEL:
+       case MSG_SMS_DATA_MSG:
+       {
+               break;
+       }
+
+       default:
+       {
+               msgWords = (msg->xMsgHeader.msgLength -
+                               sizeof(struct SmsMsgHdr_ST))/4;
+
+               for (i = 0; i < msgWords; i++)
+                       msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+               break;
+       }
+       }
+#endif /* __BIG_ENDIAN */
+}
+
+void smsendian_handle_message_header(void *msg)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
+
+       phdr->msgType = le16_to_cpu(phdr->msgType);
+       phdr->msgLength = le16_to_cpu(phdr->msgLength);
+       phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
+#endif /* __BIG_ENDIAN */
+}
+
diff --git a/drivers/cmmb/siano/smsendian.h b/drivers/cmmb/siano/smsendian.h
new file mode 100755 (executable)
index 0000000..7fbedc6
--- /dev/null
@@ -0,0 +1,32 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, 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_ENDIAN_H__
+#define __SMS_ENDIAN_H__
+
+#include <asm/byteorder.h>
+
+void smsendian_handle_tx_message(void *buffer);
+void smsendian_handle_rx_message(void *buffer);
+void smsendian_handle_message_header(void *msg);
+
+#endif /* __SMS_ENDIAN_H__ */
+
diff --git a/drivers/cmmb/siano/smsspicommon.c b/drivers/cmmb/siano/smsspicommon.c
new file mode 100755 (executable)
index 0000000..2108398
--- /dev/null
@@ -0,0 +1,439 @@
+/****************************************************************
+
+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"
+#include "smscoreapi.h"
+
+
+
+static struct _rx_buffer_st *smsspi_handle_unused_bytes_buf(
+               struct _spi_dev *dev,
+               struct _rx_buffer_st *buf, int offset, int len,
+               int unused_bytes)
+{
+       struct _rx_buffer_st *tmp_buf;
+
+
+       tmp_buf = dev->cb.allocate_rx_buf(dev->context,
+               RX_PACKET_SIZE);
+
+
+       if (!tmp_buf) {
+               sms_err("Failed to allocate RX buffer.\n");
+               return NULL;
+       }
+       if (unused_bytes > 0) {
+               /* Copy the remaining bytes to the end of
+               alignment block (256 bytes) so next read
+               will be aligned. */
+               int 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);
+       }
+       //sms_info("smsspi_handle_unused_bytes_buf unused_bytes=0x%x offset=0x%x len=0x%x \n",unused_bytes,offset,len);
+       return tmp_buf;
+}
+
+static struct _rx_buffer_st *smsspi_common_find_msg(struct _spi_dev *dev,
+               struct _rx_buffer_st *buf, int offset, int len,
+               int *unused_bytes, int *missing_bytes)
+{
+       int i;
+       int recieved_bytes, padded_msg_len;
+       int align_fix;
+       int msg_offset;
+       unsigned char *ptr = (unsigned char *)buf->ptr + offset;
+       if (unused_bytes == NULL || missing_bytes == NULL)
+               return NULL;
+
+       *missing_bytes = 0;
+       *unused_bytes = 0;
+
+       //sms_info("entering with %d bytes.\n", len);
+       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:
+                       if ((*ptr & 0xff) == 0x5a) {
+                               dev->rxState = RxsWait_e7;
+                       }
+                       else {
+                               dev->rxState = RxsWait_a5;
+                               i--;
+                               ptr--;  // re-scan current byte
+                       }
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsWait_e7:
+                       if ((*ptr & 0xff) == 0xe7) {
+                               dev->rxState = RxsWait_7e;
+                       }
+                       else {
+                               dev->rxState = RxsWait_a5;
+                               i--;
+                               ptr--;  // re-scan current byte
+                       }
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsWait_7e:
+                       if ((*ptr & 0xff) == 0x7e) {
+                               dev->rxState = RxsTypeH;
+                       }
+                       else {
+                               dev->rxState = RxsWait_a5;
+                               i--;
+                               ptr--;  // re-scan current byte
+                       }
+                       //sms_info("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;
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsTypeL:
+                       dev->rxState = RxsGetSrcId;
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsGetSrcId:
+                       dev->rxState = RxsGetDstId;
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsGetDstId:
+                       dev->rxState = RxsGetLenL;
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsGetLenL:
+                       dev->rxState = RxsGetLenH;
+                       dev->rxPacket.msg_len = (*ptr & 0xff);
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsGetLenH:
+                       dev->rxState = RxsFlagsL;
+                       dev->rxPacket.msg_len += (*ptr & 0xff) << 8;
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsFlagsL:
+                       dev->rxState = RxsFlagsH;
+                       dev->rxPacket.msg_flags = (*ptr & 0xff);
+                       //sms_info("state %d.\n", dev->rxState);
+                       break;
+               case RxsFlagsH:
+                       dev->rxState = RxsData;
+                       dev->rxPacket.msg_flags += (*ptr & 0xff) << 8;
+                       //sms_info("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;
+                               *missing_bytes = padded_msg_len -
+                                               recieved_bytes;
+
+
+                               return buf;
+                       }
+                       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;
+                                       /* The FW aligned the message data
+                                       therefore - alignment bytes should be
+                                       thrown away. Throw the alignment bytes
+                                       by moving the header ahead over the
+                                       alignment bytes. */
+                                       if (align_fix) {
+                                               int length;
+                                               ptr =
+                                                   (unsigned char *)dev->rxPacket.
+                                                   msg_buf->ptr +
+                                                   dev->rxPacket.msg_offset;
+
+                                               /* Restore header to original
+                                               state before alignment changes
+                                               */
+                                               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;
+                                       }
+                               }
+
+                               sms_info("Msg found and sent to callback func.\n");
+
+                               /* force all messages to start on
+                                * 4-byte boundary */
+                               msg_offset = dev->rxPacket.msg_offset;
+                               if (msg_offset & 0x3) {
+                                       msg_offset &= (~0x3);
+                                       memmove((unsigned char *)
+                                               (dev->rxPacket.msg_buf->ptr)
+                                               + msg_offset,
+                                               (unsigned char *)
+                                               (dev->rxPacket.msg_buf->ptr)
+                                               + dev->rxPacket.msg_offset,
+                                               dev->rxPacket.msg_len -
+                                               align_fix);
+                               }
+
+                               *unused_bytes =
+                                   len + offset - dev->rxPacket.msg_offset -
+                                   dev->rxPacket.msg_len;
+
+                               /* In any case we got here - unused_bytes
+                                * should not be 0 Because we want to force
+                                * reading at least 256 after the end
+                                of any found message */
+                               if (*unused_bytes == 0)
+                                       *unused_bytes = -1;
+
+                               buf = smsspi_handle_unused_bytes_buf(dev, buf,
+                                               offset, len, *unused_bytes);
+
+
+
+                               dev->cb.msg_found_cb(dev->context,
+                                                        dev->rxPacket.msg_buf,
+                                                        msg_offset,
+                                                        dev->rxPacket.msg_len -
+                                                        align_fix);
+
+
+                               *missing_bytes = 0;
+                               return buf;
+                       } else {
+                               sms_info("Msg found but no callback. therefore - thrown away.\n");
+                       }
+                       sms_info("state %d.\n", dev->rxState);
+                       break;
+               }
+       }
+
+       if (dev->rxState == RxsWait_a5) {
+               *unused_bytes = 0;
+               *missing_bytes = 0;
+
+               return buf;
+       } 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) {
+                       if ((*(ptr - 2) == 0xa5) || (*((unsigned int*)(ptr-4)) == *((unsigned int*)(ptr-8)))) {
+                               dev->rxState = RxsWait_a5;
+                               *unused_bytes = 0;
+                               *missing_bytes = 0;
+
+                               return buf;
+                       }
+               }
+
+               if ((dev->rxState == RxsWait_5a) && (*(ptr - 2) == 0xa5)) {
+                       dev->rxState = RxsWait_a5;
+                       *unused_bytes = 0;
+                       *missing_bytes = 0;
+
+                       return buf;
+               }
+
+               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 */
+                       struct _rx_buffer_st *tmp_buf = buf;
+                       *unused_bytes = dev->rxState - RxsWait_a5;
+                       tmp_buf = smsspi_handle_unused_bytes_buf(dev, buf,
+                                       offset, len, *unused_bytes);
+                       dev->rxState = RxsWait_a5;
+
+                       dev->cb.free_rx_buf(dev->context, buf);
+
+
+                       *missing_bytes = 0;
+                       return tmp_buf;
+               } else {
+                       /* report missing bytes and continue
+                          with message scan. */
+                       *unused_bytes = 0;
+                       *missing_bytes = SPI_PACKET_SIZE;
+                       return buf;
+               }
+       }
+}
+
+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;
+       struct _rx_buffer_st *buf, *tmp_buf;
+
+       len = 0;
+       if (!dev->cb.transfer_data_cb) {
+               sms_err("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) {
+               sms_err("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);
+                       //sms_info("transfering block of %d bytes\n", len);
+                       dev->cb.transfer_data_cb(dev->phy_context,
+                                       (unsigned char *)txbuf,
+                                       tx_phy_addr,
+                                       (unsigned char *)buf->ptr + offset,
+                                       buf->phy_addr + offset, len);
+               }
+
+               tmp_buf =
+                   smsspi_common_find_msg(dev, buf, offset, len,
+                                          &unused_bytes, &missing_bytes);
+
+
+               //sms_info("smsspi_common_transfer_msg unused_bytes=0x%x missing_bytes=0x%x\n", unused_bytes, missing_bytes);
+
+               if (bytes_to_transfer)
+                       bytes_to_transfer -= len;
+
+               if (tx_bytes)
+                       tx_bytes -= len;
+
+               if (missing_bytes)
+                       offset += len;
+
+               if (unused_bytes) {
+                       /* In this case tmp_buf is a new buffer allocated
+                        * in smsspi_common_find_msg
+                        * and it already contains the unused bytes */
+                       if (unused_bytes > 0) {
+                               align_block =
+                                   (((unused_bytes + SPI_PACKET_SIZE -
+                                      1) >> SPI_PACKET_SIZE_BITS) <<
+                                    SPI_PACKET_SIZE_BITS);
+                               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);
+                       sms_info("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,
+                     struct _spi_dev_cb_st *cb)
+{
+       sms_info("entering.\n");
+       if (cb->transfer_data_cb == 0 ||
+           cb->msg_found_cb == 0 ||
+           cb->allocate_rx_buf == 0 || cb->free_rx_buf == 0) {
+               sms_err("Invalid input parameters of init routine.\n");
+               return -1;
+       }
+       dev->context = context;
+       dev->phy_context = phy_context;
+       memcpy(&dev->cb, cb, sizeof(struct _spi_dev_cb_st));
+       dev->rxState = RxsWait_a5;
+       sms_info("exiting.\n");
+       return 0;
+}
diff --git a/drivers/cmmb/siano/smsspicommon.h b/drivers/cmmb/siano/smsspicommon.h
new file mode 100755 (executable)
index 0000000..cfcc6b1
--- /dev/null
@@ -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
+};
+
+struct _rx_buffer_st {
+       void *ptr;
+       unsigned long phy_addr;
+};
+
+struct _rx_packet_request {
+       struct _rx_buffer_st *msg_buf;
+       int msg_offset;
+       int msg_len;
+       int msg_flags;
+};
+
+struct _spi_dev_cb_st{
+       void (*transfer_data_cb) (void *context, unsigned char *, unsigned long,
+                                 unsigned char *, unsigned long, int);
+       void (*msg_found_cb) (void *, void *, int, int);
+       struct _rx_buffer_st *(*allocate_rx_buf) (void *, int);
+       void (*free_rx_buf) (void *, struct _rx_buffer_st *);
+};
+
+struct _spi_dev {
+       void *context;
+       void *phy_context;
+       struct _spi_dev_cb_st cb;
+       char *rxbuf;
+       enum _spi_rx_state rxState;
+       struct _rx_packet_request rxPacket;
+       char *internal_tx_buf;
+};
+
+struct _spi_msg {
+       char *buf;
+       unsigned long buf_phy_addr;
+       int len;
+};
+
+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,
+                     struct _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 --git a/drivers/cmmb/siano/smsspilog.c b/drivers/cmmb/siano/smsspilog.c
new file mode 100755 (executable)
index 0000000..a623b13
--- /dev/null
@@ -0,0 +1,625 @@
+/****************************************************************
+
+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 <linux/delay.h>
+#include <mach/gpio.h>
+#include "smscoreapi.h"
+#include "smsdbg_prn.h"
+#include "smsspicommon.h"
+#include "smsspiphy.h"
+#include <linux/spi/spi.h>
+
+#define ANDROID_2_6_25
+#ifdef ANDROID_2_6_25
+#include <linux/workqueue.h>
+#endif
+
+#define DRV_NAME       "siano1186"
+
+
+#define SMS_INTR_PIN                   19  /* 0 for nova sip, 26 for vega in the default, 19 in the reality */
+#define TX_BUFFER_SIZE                 0x200
+#define RX_BUFFER_SIZE                 (0x1000 + SPI_PACKET_SIZE + 0x100)
+#define NUM_RX_BUFFERS                 64 // change to 128
+//#define NUM_RX_BUFFERS                       72
+
+
+u32 g_Sms_Int_Counter=0;
+u32 g_Sms_MsgFound_Counter=0;
+
+extern unsigned  long   u_irq_count;
+
+struct _spi_device_st {
+       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;
+};
+
+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 *);
+};
+
+struct _spi_device_st *spi_dev;
+
+static int spi_resume_fail = 0 ;
+static int spi_suspended   = 0 ;
+
+
+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 };
+
+// to support dma 16byte burst size
+static u8 smsspi_startup[] = { 0,0,0,0,0,0,0,0,0, 0, 0xde, 0xc1, 0xa5, 0x51, 0xf1, 0xed };
+
+//static u32 default_type = SMS_NOVA_A0;
+static u32 default_type = SMS_VEGA;
+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.");
+
+/******************************************/
+
+void spilog_panic_print(void)
+{
+    if(spi_dev)
+    {
+        printk("spidev rxbuf_phy_addr =[0x%x]\n",spi_dev->rxbuf_phy_addr) ;
+        printk("spidev txbufphy_addr  =[0x%x]\n",spi_dev->txbuf_phy_addr) ;
+        printk("spidev TX_BUFFER_SIZE = [0x%x]\n",TX_BUFFER_SIZE) ;
+    }
+}
+
+static void spi_worker_thread(void *arg)
+{
+       struct _spi_device_st *spi_device = spi_dev;
+       struct _smsspi_txmsg *msg = NULL;
+       struct _spi_msg txmsg;
+       int i=0;
+
+       PDEBUG("worker start\n");
+       do {
+        /* do we have a msg to write ? */
+               if (!msg && !list_empty(&spi_device->txqueue))
+                       msg = (struct _smsspi_txmsg *)list_entry(spi_device->txqueue.next, struct _smsspi_txmsg, node);
+        if (msg) {
+                       if (msg->add_preamble) {// need to 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 = (char*)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);
+                if(spi_resume_fail||spi_suspended) 
+                {
+                    printk(KERN_EMERG " SMS1180: spi failed\n");
+                } else {
+                    smsspi_common_transfer_msg(&spi_device->dev, &txmsg, 1);
+                }
+                       } else {// donot need to add preamble
+                               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 = (char*)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);
+                if(spi_resume_fail||spi_suspended) 
+                {
+                    printk(KERN_EMERG " SMS1180: spi failed\n");
+                } else {
+                    smsspi_common_transfer_msg(&spi_device->dev,&txmsg, 0);
+                }
+                       }
+               } else {
+            if(spi_resume_fail||spi_suspended) 
+            {
+                printk(KERN_EMERG " SMS1180: spi failed\n") ;     
+            } 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 ? */
+
+
+               //check if we lost msg, if so, recover
+               if(g_Sms_MsgFound_Counter < g_Sms_Int_Counter)
+               {
+                       printk("we lost msg, probably becouse dma time out\n");
+                       //for(i=0; i<16; i++)
+                       {
+                               //smsspi_common_transfer_msg(&spi_device->dev, NULL, 1);
+                       }
+                       g_Sms_MsgFound_Counter = g_Sms_Int_Counter;
+               }
+       } while (!list_empty(&spi_device->txqueue) || msg);
+
+}
+
+unsigned  long u_msgres_count =0;
+static void msg_found(void *context, void *buf, int offset, int len)
+{
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+       struct smscore_buffer_t *cb =
+           (struct smscore_buffer_t
+            *)(container_of(buf, struct smscore_buffer_t, p));
+
+    g_Sms_MsgFound_Counter++;
+    u_msgres_count ++;
+    
+    //sms_debug("Msg_found count = %d\n", u_msgres_count);
+
+    if(len > RX_BUFFER_SIZE || offset >RX_BUFFER_SIZE )
+    {
+        printk("SMS1180: msg rx over,len=0x%x,offset=0x%x\n",len,offset ) ;
+        printk("SMS1180: cb->p = [0x%x]\n",(unsigned int) cb->p) ;
+        printk("SMS1180: cb->phys=[0x%x]\n",(unsigned int) cb->phys) ;
+    } 
+    
+       cb->offset = offset;
+       cb->size = len;
+
+       smscore_onresponse(spi_device->coredev, cb);
+
+
+}
+
+static void smsspi_int_handler(void *context)
+{
+       g_Sms_Int_Counter++;
+    
+    if(spi_resume_fail||spi_suspended) 
+    {
+        printk(KERN_EMERG " SMS1180: spi failed\n") ;
+        return ;                       
+    }  
+       schedule_work(&spi_work_queue);
+}
+
+
+
+static int smsspi_queue_message_and_wait(struct _spi_device_st *spi_device,
+                                        struct _smsspi_txmsg *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_SetIntLine(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, 100}
+       };
+       struct _smsspi_txmsg msg;
+
+       PDEBUG("Sending SPI Set Interrupt command sequence\n");
+    sms_info("Sending SPI Set Interrupt command sequence\n");
+       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; */
+       smsspi_queue_message_and_wait(context, &msg);
+       return 0;
+}
+
+
+static int smsspi_preload(void *context)
+{
+       struct _smsspi_txmsg msg;
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+    int ret;
+
+       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;
+
+    printk(KERN_EMERG "smsmdtv: call smsspi_queue_message_and_wait\n") ;
+       smsspi_queue_message_and_wait(context, &msg);
+
+
+       ret = smsspi_SetIntLine(context);
+        sms_info("smsspi_preload set int line ret = 0x%x",ret);
+    //return ret;
+       return 0;
+
+}
+
+
+static int smsspi_postload(void *context)
+{
+       struct _Msg {
+               struct SmsMsgHdr_ST hdr;
+               u32 data[1];
+       } Msg = {
+               {
+               MSG_SMS_SET_PERIODIC_STATS_REQ, 0, HIF_TASK,
+                           sizeof(struct _Msg), 0}, {
+               1}
+       };
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+       struct _smsspi_txmsg msg;
+
+       sms_debug("Sending Period Statistics Req\n");
+    
+    //This function just speed up the SPI clock
+       fwDnlComplete(spi_device->phy_dev, 0);
+       msg.buffer = &Msg;
+       msg.size = sizeof(Msg);
+       msg.alignment = SPI_PACKET_SIZE;
+       msg.add_preamble = 0;
+       msg.prewrite = NULL;
+       msg.postwrite = NULL;   /* smsspiphy_restore_clock; */
+
+       //smsspi_queue_message_and_wait(context, &msg);
+       msleep(50);
+       g_Sms_Int_Counter=0;
+       g_Sms_Int_Counter=0;
+
+       u_irq_count = 0;
+
+       return 0;
+}
+
+
+static int smsspi_write(void *context, void *txbuf, size_t len)
+{
+       struct _smsspi_txmsg 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;
+       }
+
+       return smsspi_queue_message_and_wait(context, &msg);
+}
+
+struct _rx_buffer_st *allocate_rx_buf(void *context, int size)
+{
+       struct smscore_buffer_t *buf;
+       struct _spi_device_st *spi_device = (struct _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);
+//     printk("smsmdtv: 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 */
+
+//  smscore_getbuffer return null, lets also return null
+       if(NULL == buf)
+       {
+               return NULL;
+       }
+
+       return (struct _rx_buffer_st *) &buf->p;
+}
+
+static void free_rx_buf(void *context, struct _rx_buffer_st *buf)
+{
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+       struct smscore_buffer_t *cb =
+           (struct smscore_buffer_t
+            *)(container_of(((void *)buf), struct smscore_buffer_t, p));
+//     printk("smsmdtv: 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 int smsspi_driver_probe(struct platform_device *pdev)
+{
+    PDEBUG("smsspi_probe\n") ;
+    return 0 ;
+}
+
+extern void smschar_reset_device(void) ;
+extern void smschar_set_suspend(int suspend_on);
+
+extern int sms_suspend_count ;
+
+#if 0   //hzb rockchip@20100525 
+static struct platform_device smsspi_device = {
+       .name = "smsspi",
+       .id = 1,
+       .dev = {
+               .release = smsspi_release,
+               },
+};
+#endif
+
+static struct platform_driver smsspi_driver = {
+    .probe   = smsspi_driver_probe,
+
+    .driver  = {
+         .name = "smsspi",
+    },       
+};
+
+void smsspi_poweron(void)
+{
+    int ret=0;
+    ret = smsspibus_ssp_resume(spi_dev->phy_dev) ;
+    if( ret== -1)
+    {
+       printk(KERN_INFO "smsspibus_ssp_resume failed\n") ;
+
+       }
+}
+
+
+void smsspi_off(void)
+{
+    smschar_reset_device() ;
+
+    smsspibus_ssp_suspend(spi_dev->phy_dev) ;
+}
+
+
+static int siano1186_probe( struct spi_device *Smsdevice)
+{
+    struct smsdevice_params_t params;
+    int ret;
+    struct _spi_device_st *spi_device;
+    struct _spi_dev_cb_st common_cb;
+
+    sms_debug(KERN_INFO "siano1186_probe\n") ;
+
+    spi_device =
+    kmalloc(sizeof(struct _spi_device_st), GFP_KERNEL);
+    if(!spi_device)
+    {
+        printk("spi_device is null smsspi_register\n") ;
+        return 0;
+    }
+    spi_dev = spi_device;
+
+    INIT_LIST_HEAD(&spi_device->txqueue);
+
+#if 0
+    spi_device->txbuf = kmalloc(max(TX_BUFFER_SIZE,PAGE_SIZE),GFP_KERNEL|GFP_DMA);
+    spi_device->txbuf_phy_addr = __pa(spi_device->txbuf);
+#else
+    spi_device->txbuf = dma_alloc_coherent(NULL, max(TX_BUFFER_SIZE,PAGE_SIZE),&spi_device->txbuf_phy_addr, GFP_KERNEL | GFP_DMA);
+#endif
+
+    if (!spi_device->txbuf) {
+        printk(KERN_INFO "%s dma_alloc_coherent(...) failed\n", __func__);
+        ret = -ENOMEM;
+        goto txbuf_error;
+    }
+    
+    sms_debug(KERN_INFO "smsmdtv: spi_device->txbuf = 0x%x  spi_device->txbuf_phy_addr= 0x%x\n",
+            (unsigned int)spi_device->txbuf, spi_device->txbuf_phy_addr);
+
+    spi_device->phy_dev =  smsspiphy_init(Smsdevice, 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 = &Smsdevice->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;
+    }
+    spi_resume_fail = 0 ;
+    spi_suspended = 0 ;
+    printk(KERN_INFO "siano1186_probe exiting\n") ;
+   
+    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:
+    
+#if 0  //spi buff kmalloc  
+    kfree(spi_device->txbuf);
+#else
+    dma_free_coherent(NULL, TX_BUFFER_SIZE, spi_device->txbuf,spi_device->txbuf_phy_addr);
+#endif
+
+txbuf_error:
+    sms_err("exiting error %d\n", ret);
+
+    return ret;
+}
+
+
+static struct spi_driver siano1186_driver = {
+       .driver = {
+                  .name = DRV_NAME,
+                  .bus = &spi_bus_type,
+                  .owner = THIS_MODULE,
+                  },
+       .probe = siano1186_probe,
+       //.remove = __devexit_p(siano1186_remove),
+};
+
+
+
+int smsspi_register(void)
+{
+    printk(KERN_INFO "smsmdtv: in smsspi_register\n") ;
+    spi_register_driver(&siano1186_driver); 
+}
+
+void smsspi_unregister(void)
+{
+       struct _spi_device_st *spi_device = spi_dev;
+       printk(KERN_INFO "smsmdtv: in smsspi_unregister\n") ;
+
+       PDEBUG("entering\n");
+
+       /* stop interrupts */
+       smsspiphy_deinit(spi_device->phy_dev);
+       smscore_unregister_device(spi_device->coredev);
+
+#if 0   //spi buff kmalloc  
+    kfree(spi_device->txbuf);
+#else
+       dma_free_coherent(NULL, TX_BUFFER_SIZE, spi_device->txbuf,spi_device->txbuf_phy_addr);
+#endif    
+
+       PDEBUG("exiting\n");
+}
diff --git a/drivers/cmmb/siano/smsspiphy.h b/drivers/cmmb/siano/smsspiphy.h
new file mode 100755 (executable)
index 0000000..55d76b9
--- /dev/null
@@ -0,0 +1,38 @@
+/****************************************************************
+
+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);
+void smsspibus_ssp_suspend(void* context );
+int  smsspibus_ssp_resume(void* context);
+
+#endif /* __SMS_SPI_PHY_H__ */
diff --git a/drivers/cmmb/siano/smsspiphy_pxa.c b/drivers/cmmb/siano/smsspiphy_pxa.c
new file mode 100755 (executable)
index 0000000..5215093
--- /dev/null
@@ -0,0 +1,732 @@
+/****************************************************************
+
+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>
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#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 <asm/io.h>
+#include "smsdbg_prn.h"
+#include <linux/spi/spi.h>
+#include <asm/arch/gpio.h>
+#include "smscoreapi.h"
+
+
+#define CMMB_1186_SPIIRQ GPIOPortE_Pin1//This Pin is SDK Board GPIOPortE_Pin1 
+
+
+#define SSP_PORT 1
+#define SSP_CKEN CKEN_SSP1
+#define SMS_IRQ_GPIO MFP_PIN_GPIO5
+
+#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
+
+
+/* Macros defining physical layer behaviour*/
+#ifdef PXA_310_LV
+#define CLOCK_FACTOR 1
+//#define CLOCK_FACTOR 2
+#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
+
+
+
+// in android platform 2.6.25 , need to check the Reg bit by bit later
+#define GSDR(x) __REG2(0x40e00400, ((x) & 0x60) >> 3)
+#define GCDR(x) __REG2(0x40300420, ((x) & 0x60) >> 3)
+
+#define GSRER(x) __REG2(0x40e00440, ((x) & 0x60) >> 3)
+#define GCRER(x) __REG2(0x40e00460, ((x) & 0x60) >> 3)
+
+
+#define GPIO_DIR_IN 0
+
+#define SSCR0_P1       __REG(0x41000000)  /* SSP Port 1 Control Register 0 */
+#define SSCR1_P1       __REG(0x41000004)  /* SSP Port 1 Control Register 1 */
+#define SSSR_P1                __REG(0x41000008)  /* SSP Port 1 Status Register */
+#define SSITR_P1       __REG(0x4100000C)  /* SSP Port 1 Interrupt Test Register */
+#define SSDR_P1                __REG(0x41000010)  /* (Write / Read) SSP Port 1 Data Write Register/SSP Data Read Register */
+
+unsigned  long u_irq_count =0;
+
+
+/**********************************************************************/
+//to support dma 16byte burst size
+// change SPI TS according to marvel recomendations
+
+#define DMA_BURST_SIZE         DCMD_BURST16      //DCMD_BURST8 
+#define SPI_RX_FIFO_RFT        SSCR1_RxTresh(4) //SSCR1_RxTresh(1) 
+#define SPI_TX_FIFO_TFT                SSCR1_TxTresh(3) //SSCR1_TxTresh(1) 
+
+
+/**********************************************************************/
+
+#include <linux/notifier.h>
+
+static unsigned int dma_rxbuf_phy_addr ;
+static unsigned int dma_txbuf_phy_addr ;
+
+static int     rx_dma_channel =0 ;
+static int     tx_dma_channel =0 ;
+static volatile int     dma_len = 0 ;
+static volatile int     tx_len  = 0 ;
+
+static struct ssp_dev*  panic_sspdev = NULL ;
+
+
+extern void smscore_panic_print(void);
+extern void spilog_panic_print(void) ;
+static void chip_powerdown();
+extern void smschar_reset_device(void);
+
+static int sms_panic_handler(struct notifier_block *this,
+                             unsigned long         event,
+                             void                  *unused) 
+{
+    static int panic_event_handled = 0;
+    if(!panic_event_handled)
+    {
+       smscore_panic_print() ;
+       spilog_panic_print() ; 
+       printk("last tx_len = %d\n",tx_len) ;
+       printk("last DMA len = %d\n",dma_len) ;
+#if 0       
+       printk("rxbuf_addr=[0x%x],Rx DSADR=[0x%x] DTADR=[0x%x] DCSR=[0x%x] DCMD=[0x%x]\n",
+                             dma_rxbuf_phy_addr, DSADR(rx_dma_channel),DTADR(rx_dma_channel), 
+                             DCSR(rx_dma_channel),DCMD(rx_dma_channel) );
+
+       printk("txbuf_addr=[0x%x],Tx DSADR=[0x%x] DTADR=[0x%x] DCSR[0x%x] DCMD=[0x%x]\n", 
+                             dma_txbuf_phy_addr, DSADR(tx_dma_channel),DTADR(tx_dma_channel),
+                             DCSR(tx_dma_channel),DCMD(tx_dma_channel) );
+       if(panic_sspdev)
+       {
+           printk("SSCR0 =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSCR0)) ;
+           printk("SSCR1 =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSCR1)) ;
+           printk("SSTO  =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSTO)) ;
+           printk("SSPSP =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSPSP)) ;
+           printk("SSSR  =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSSR)) ;
+       }
+#endif
+
+       panic_event_handled =1 ; 
+    }
+    return NOTIFY_OK ;
+}
+
+static struct notifier_block sms_panic_notifier = {
+       .notifier_call  = sms_panic_handler,
+       .next           = NULL,
+       .priority       = 150   /* priority: INT_MAX >= x >= 0 */
+};
+
+
+
+
+/*!  GPIO functions for PXA3xx
+*/
+// obsolete
+void pxa3xx_gpio_set_rising_edge_detect (int gpio_id, int dir)
+{
+#if 0
+    unsigned  long flags;
+       int gpio = mfp_to_gpio(gpio_id);
+
+//     if (gpio >= GPIO_EXP_START)
+//     {
+//             return 0;
+//     }
+//     spin_lock_irqsave(&gpio_spin_lock, flags);
+       local_irq_save(flags);
+        
+        if ( dir == GPIO_DIR_IN)
+               GCRER(gpio) =1u << (gpio& 0x1f);
+       else
+               GSRER(gpio) =1u << (gpio& 0x1f);
+       local_irq_restore(flags);
+#endif
+}
+
+void pxa3xx_gpio_set_direction(int gpio_id , int dir)
+{
+#if 0
+    unsigned long flags;
+       int gpio = mfp_to_gpio(gpio_id);
+
+       local_irq_save(flags);
+        
+        if ( dir == GPIO_DIR_IN)
+               GCDR(gpio) =1u << (gpio& 0x1f);
+       else
+               GSDR(gpio) =1u << (gpio& 0x1f);
+       local_irq_restore(flags);
+#endif
+}
+//////////////////////////////////////////////////////////
+
+/* physical layer variables */
+/*! global bus data */
+struct spiphy_dev_s {
+       //struct ssp_dev sspdev;        /*!< ssp port configuration */
+       struct completion transfer_in_process;
+    struct spi_device *Smsdevice; 
+       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;
+};
+
+
+
+
+/*!
+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(struct spiphy_dev_s *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)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+    
+       u_irq_count ++;
+    
+       PDEBUG("INT counter = %d\n", u_irq_count);
+
+    sms_debug("spibus_interrupt\n");
+    
+       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
+*/
+
+//extern dma_addr_t common_buf_end ;
+
+static void spibus_dma_handler(int channel, void *context)
+{
+#if 0
+    struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+//     printk( "recieved interrupt from dma channel %d irq status %x.\n",
+//            channel, irq_status);
+       if (irq_status & DCSR_BUSERR) {
+               printk(KERN_EMERG "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);
+#endif   
+}
+
+void smsspibus_xfer(void *context, unsigned char *txbuf,
+                   unsigned long txbuf_phy_addr, unsigned char *rxbuf,
+                   unsigned long rxbuf_phy_addr, int len)
+{
+    struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+    unsigned char *temp = NULL;
+    int ret;
+
+    //printk(KERN_INFO "smsspibus_xfer \n");
+    //printk(KERN_INFO "smsspibus_xfer txbuf = 0x%x\n",txbuf);
+    //printk(KERN_INFO "smsspibus_xfer rxbuf = 0x%x\n",rxbuf);
+    //printk(KERN_INFO "smsspibus_xfer len=0x%x\n",len);
+
+    //while (1)
+    //{
+    //mdelay(100);    
+#if 1
+    if (txbuf)
+    {
+       // sms_debug("spi write buf[4] = 0x%x buf[5] = 0x%x\n", txbuf[4],txbuf[5]);
+        ret = spi_write(spiphy_dev->Smsdevice, txbuf, len);
+    }
+   
+#if 0    
+    else
+    {
+        temp = kmalloc(len,GFP_KERNEL);
+        if (temp == NULL)
+        {
+            sms_err("sms spi write temp malloc fail");
+            return -ENOMEM;
+        }
+        memset(temp,0xFF,len);
+        sms_debug("sms spi write temp buf");
+        ret = spi_write(spiphy_dev->Smsdevice, temp, len);
+    }
+#endif    
+//    if (ret)
+ //       sms_err(KERN_INFO "smsspibus_xfer spi write ret=0x%x\n",ret);
+
+//      memset (rxbuf, 0xff, 256);
+
+        
+    if ((rxbuf)&&(len != 16))
+        ret = spi_read(spiphy_dev->Smsdevice, rxbuf, len);
+    
+    //sms_debug("sms spi read buf=0x%x\n",rxbuf[0]);
+    //sms_debug("sms spi read buf=0x%x\n",rxbuf[1]);
+    //sms_debug("sms spi read buf=0x%x\n",rxbuf[2]);
+    //sms_debug("sms spi read buf=0x%x\n",rxbuf[3]);
+//        printk(KERN_INFO "after sms spi read buf[0]=0x%x\n",rxbuf[0]);
+       
+  //      printk(KERN_INFO "sms spi read buf[8]=0x%x\n",rxbuf[8]);
+    //    printk(KERN_INFO "sms spi read buf[9]=0x%x\n",rxbuf[9]);
+    //}
+#else
+    spi_write_then_read(spiphy_dev->Smsdevice,txbuf,len,rxbuf,len);
+#endif
+    //spi_write_then_read(struct spi_device *spi, const u8 *txbuf, unsigned n_tx, u8 *rxbuf, unsigned n_rx);
+#if 0   //hzb 0524
+    /* DMA burst is 8 bytes, therefore we need tmp buffer that size. */
+       // to support dma 16byte burst size
+       unsigned long tmp[4];
+       //unsigned long tmp[2];
+
+       unsigned long txdma;
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+        unsigned long expire;
+       int res =0;
+
+        expire =  msecs_to_jiffies(200) ;
+       /* program the controller */
+       if (txbuf)
+       {
+//             PDEBUG("tx \n");
+               invert_endianness(txbuf, len);
+       }
+//     else
+//             PDEBUG("rx \n");
+       tmp[0] = -1;
+       tmp[1] = -1;
+       tmp[2] = -1;
+       tmp[3] = -1;
+
+       /* map RX buffer */
+
+       if (!txbuf)
+        {
+               txdma =
+                   dma_map_buf(spiphy_dev, (char *)tmp, sizeof(tmp),
+                               DMA_TO_DEVICE);
+                tx_len = 0 ;
+        }
+       else
+        {
+               txdma = txbuf_phy_addr;
+                tx_len = len ;
+        }
+
+       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;
+
+
+        // to support dma 16byte burst size
+       DCMD(spiphy_dev->rx_dma_channel) = DCMD_INCTRGADDR | DCMD_FLOWSRC
+           | DCMD_WIDTH4 | DCMD_ENDIRQEN | DMA_BURST_SIZE | len;
+
+
+
+        rx_dma_channel = spiphy_dev->rx_dma_channel ;
+        dma_rxbuf_phy_addr = (unsigned int) rxbuf_phy_addr ;
+        dma_len = 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;
+       
+        tx_dma_channel = spiphy_dev->tx_dma_channel;
+        dma_txbuf_phy_addr = (unsigned int) txdma ;
+
+       if (txbuf) {
+               DCMD(spiphy_dev->tx_dma_channel) =
+                   DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_WIDTH4
+                   /* | DCMD_ENDIRQEN */  | DMA_BURST_SIZE  | len;
+               spiphy_dev->tx_buf_len = len;
+       } else {
+               DCMD(spiphy_dev->tx_dma_channel) = DCMD_FLOWTRG
+                   | DCMD_WIDTH4 /* | DCMD_ENDIRQEN */  |DMA_BURST_SIZE  | len;
+               spiphy_dev->tx_buf_len = 4;
+       }
+
+#if 0
+       printk("Tx DSADR=[0x%x],DTADR=[0x%x],DCMD=[0x%x],len =[0x%x]\n",
+                DSADR(spiphy_dev->tx_dma_channel),DTADR(spiphy_dev->tx_dma_channel),DCMD(spiphy_dev->tx_dma_channel),len) ;
+#endif 
+//     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 */
+ //printk( "smsmdtv: Start DMA controller\n");   
+       DCSR(spiphy_dev->rx_dma_channel) |= DCSR_RUN;
+       DCSR(spiphy_dev->tx_dma_channel) |= DCSR_RUN;
+//     printk(  "DMA running. wait for completion.\n");
+
+//printk( "smsmdtv: before wait_for_completion_timeout\n");
+       res = wait_for_completion_timeout(&spiphy_dev->transfer_in_process,expire);       
+       if(!res)
+       {
+             printk( "smsmdtv DMA timeout, res=0x%x len =%d\n", res, len);
+             printk( "smsmdtv DMA reg, 0x%x %x \n",DCSR(spiphy_dev->rx_dma_channel), DCSR(spiphy_dev->tx_dma_channel)  );
+             DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+            DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL;
+            
+             complete(&spiphy_dev->transfer_in_process);
+        }
+//     else
+       {
+               //printk( "DMA complete.\n");
+               invert_endianness(rxbuf, len);
+
+               if (!txbuf)
+                       PDEBUG("rx[4]:0x%x;[6]:0x%x \n", rxbuf[4], rxbuf[6]);
+       }
+//printk( "smsmdtv: Xfer end\n");
+#endif //hzb 0524
+}
+
+void smschipreset(void *context)
+{
+
+}
+
+static struct ssp_state  sms_ssp_state ;
+
+void smsspibus_ssp_suspend(void* context )
+{
+    struct spiphy_dev_s *spiphy_dev ;
+    printk("entering smsspibus_ssp_suspend\n");
+    if(!context)
+    {
+        PERROR("smsspibus_ssp_suspend context NULL \n") ;
+        return ;
+    }
+    spiphy_dev = (struct spiphy_dev_s *) context;
+
+    //ssp_flush(&(spiphy_dev->sspdev)) ;
+    //ssp_save_state(&(spiphy_dev->sspdev) , &sms_ssp_state) ;
+    //ssp_disable(&(spiphy_dev->sspdev));
+    //ssp_exit(&spiphy_dev->sspdev);
+    free_irq(CMMB_1186_SPIIRQ, spiphy_dev);
+
+       /*  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);
+       chip_powerdown();
+    
+}
+static void chip_poweron()
+{
+#if 0    
+#ifdef CONFIG_MACH_LC6830_PHONE_BOARD_1_0
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 1);
+       mdelay(100);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 1);
+       mdelay(1);
+#elif defined CONFIG_MACH_LC6830_PHONE_BOARD_1_1
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 1);
+       mdelay(50);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO8), 1);
+       mdelay(200);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 1);
+       mdelay(1);
+#endif
+#endif
+}
+
+static void chip_powerdown()
+{
+#if 0    //hzb test
+#ifdef CONFIG_MACH_LC6830_PHONE_BOARD_1_0
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 0);
+       mdelay(50);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 0);
+#elif defined CONFIG_MACH_LC6830_PHONE_BOARD_1_1
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 0);
+       mdelay(100);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO8), 0);
+       mdelay(100);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 0);
+       mdelay(1);
+#endif
+#endif
+}
+
+int smsspibus_ssp_resume(void* context) 
+{
+    int ret;
+    struct spiphy_dev_s *spiphy_dev ;
+    u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+    printk("entering smsspibus_ssp_resume\n");
+
+    if(!context){
+        PERROR("smsspibus_ssp_resume context NULL \n");
+        return -1;
+    }
+    spiphy_dev = (struct spiphy_dev_s *) context;
+    chip_poweron();
+    //ret = ssp_init(&spiphy_dev->sspdev, SSP_PORT, 0);
+    //if (ret) {
+        //PERROR("ssp_init failed. error %d", ret);
+    //}
+    //GPIOPullUpDown(CMMB_1186_SPIIRQ, IRQT_FALLING);
+    //err = request_gpio_irq(PT2046_PENIRQ,xpt2046_ts_interrupt,GPIOEdgelFalling,ts_dev);   
+    //ret = request_gpio_irq(CMMB_1186_SPIIRQ, (pFunc)spibus_interrupt, GPIOEdgelRising, spiphy_dev);       
+    if(ret<0){
+        printk("siano1186 request irq failed !!\n");
+        ret = -EBUSY;
+        goto fail1;
+    }
+    return 0 ;
+fail1:
+       free_irq(CMMB_1186_SPIIRQ,NULL);
+    return -1 ;
+}
+
+
+void *smsspiphy_init(void *context, void (*smsspi_interruptHandler) (void *),
+                    void *intr_context)
+{
+       int ret;
+       struct spiphy_dev_s *spiphy_dev;
+       u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+
+    sms_debug("smsspiphy_init\n");
+    
+       spiphy_dev = kmalloc(sizeof(struct spiphy_dev_s), GFP_KERNEL);
+    if(!spiphy_dev )
+    {
+        printk("spiphy_dev is null in smsspiphy_init\n") ;
+        return NULL;
+       }
+       chip_powerdown();
+       spiphy_dev->interruptHandler = smsspi_interruptHandler;
+       spiphy_dev->intr_context = intr_context;
+    spiphy_dev->Smsdevice = (struct spi_device*)context;
+    
+    GPIOPullUpDown(CMMB_1186_SPIIRQ, IRQT_FALLING);
+
+    ret = request_gpio_irq(CMMB_1186_SPIIRQ, spibus_interrupt, GPIOEdgelRising, spiphy_dev);//
+    
+    if(ret<0){
+        printk("siano 1186 request irq failed !!\n");
+        ret = -EBUSY;
+        goto fail1;
+    }
+    
+    atomic_notifier_chain_register(&panic_notifier_list,&sms_panic_notifier);
+    //panic_sspdev =  &(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");
+       printk("exiting on error\n");
+fail1:
+    free_irq(CMMB_1186_SPIIRQ,NULL);
+       return 0;
+}
+
+int smsspiphy_deinit(void *context)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       PDEBUG("entering\n");
+
+       printk("entering smsspiphy_deinit\n");
+
+        panic_sspdev = NULL;
+        atomic_notifier_chain_unregister(&panic_notifier_list,
+                                                &sms_panic_notifier);
+        chip_powerdown();
+       PDEBUG("exiting\n");
+       return 0;
+}
+
+void smsspiphy_set_config(struct spiphy_dev_s *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 = SPI_RX_FIFO_RFT |SPI_TX_FIFO_TFT | 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)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       smsspiphy_set_config(spiphy_dev, 3);
+       msleep(100);
+}
+
+void fwDnlComplete(void *context, int App)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       smsspiphy_set_config(spiphy_dev, 1);
+       msleep(100);
+}
diff --git a/drivers/cmmb/siano/smsspiphy_rk.c b/drivers/cmmb/siano/smsspiphy_rk.c
new file mode 100755 (executable)
index 0000000..b61128a
--- /dev/null
@@ -0,0 +1,631 @@
+/****************************************************************
+
+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>
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#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 <asm/io.h>
+#include "smsdbg_prn.h"
+#include <linux/spi/spi.h>
+#include <mach/gpio.h>
+#include "smscoreapi.h"
+
+
+
+
+#define SSP_PORT 1
+#define SSP_CKEN CKEN_SSP1
+#define SMS_IRQ_GPIO MFP_PIN_GPIO5
+
+#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
+
+
+/* Macros defining physical layer behaviour*/
+#ifdef PXA_310_LV
+#define CLOCK_FACTOR 1
+//#define CLOCK_FACTOR 2
+#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
+
+
+
+// in android platform 2.6.25 , need to check the Reg bit by bit later
+#define GSDR(x) __REG2(0x40e00400, ((x) & 0x60) >> 3)
+#define GCDR(x) __REG2(0x40300420, ((x) & 0x60) >> 3)
+
+#define GSRER(x) __REG2(0x40e00440, ((x) & 0x60) >> 3)
+#define GCRER(x) __REG2(0x40e00460, ((x) & 0x60) >> 3)
+
+
+#define GPIO_DIR_IN 0
+
+#define SSCR0_P1       __REG(0x41000000)  /* SSP Port 1 Control Register 0 */
+#define SSCR1_P1       __REG(0x41000004)  /* SSP Port 1 Control Register 1 */
+#define SSSR_P1                __REG(0x41000008)  /* SSP Port 1 Status Register */
+#define SSITR_P1       __REG(0x4100000C)  /* SSP Port 1 Interrupt Test Register */
+#define SSDR_P1                __REG(0x41000010)  /* (Write / Read) SSP Port 1 Data Write Register/SSP Data Read Register */
+
+unsigned  long u_irq_count =0;
+
+
+/**********************************************************************/
+//to support dma 16byte burst size
+// change SPI TS according to marvel recomendations
+
+#define DMA_BURST_SIZE         DCMD_BURST16      //DCMD_BURST8 
+#define SPI_RX_FIFO_RFT        SSCR1_RxTresh(4) //SSCR1_RxTresh(1) 
+#define SPI_TX_FIFO_TFT                SSCR1_TxTresh(3) //SSCR1_TxTresh(1) 
+
+
+/**********************************************************************/
+
+#include <linux/notifier.h>
+
+static unsigned int dma_rxbuf_phy_addr ;
+static unsigned int dma_txbuf_phy_addr ;
+
+static int     rx_dma_channel =0 ;
+static int     tx_dma_channel =0 ;
+static volatile int     dma_len = 0 ;
+static volatile int     tx_len  = 0 ;
+
+static struct ssp_dev*  panic_sspdev = NULL ;
+
+
+extern void smscore_panic_print(void);
+extern void spilog_panic_print(void) ;
+static void chip_powerdown();
+extern void smschar_reset_device(void);
+
+static int sms_panic_handler(struct notifier_block *this,
+                             unsigned long         event,
+                             void                  *unused) 
+{
+    static int panic_event_handled = 0;
+    if(!panic_event_handled)
+    {
+       smscore_panic_print() ;
+       spilog_panic_print() ; 
+       printk("last tx_len = %d\n",tx_len) ;
+       printk("last DMA len = %d\n",dma_len) ;
+#if 0       
+       printk("rxbuf_addr=[0x%x],Rx DSADR=[0x%x] DTADR=[0x%x] DCSR=[0x%x] DCMD=[0x%x]\n",
+                             dma_rxbuf_phy_addr, DSADR(rx_dma_channel),DTADR(rx_dma_channel), 
+                             DCSR(rx_dma_channel),DCMD(rx_dma_channel) );
+
+       printk("txbuf_addr=[0x%x],Tx DSADR=[0x%x] DTADR=[0x%x] DCSR[0x%x] DCMD=[0x%x]\n", 
+                             dma_txbuf_phy_addr, DSADR(tx_dma_channel),DTADR(tx_dma_channel),
+                             DCSR(tx_dma_channel),DCMD(tx_dma_channel) );
+       if(panic_sspdev)
+       {
+           printk("SSCR0 =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSCR0)) ;
+           printk("SSCR1 =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSCR1)) ;
+           printk("SSTO  =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSTO)) ;
+           printk("SSPSP =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSPSP)) ;
+           printk("SSSR  =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSSR)) ;
+       }
+#endif
+
+       panic_event_handled =1 ; 
+    }
+    return NOTIFY_OK ;
+}
+
+static struct notifier_block sms_panic_notifier = {
+       .notifier_call  = sms_panic_handler,
+       .next           = NULL,
+       .priority       = 150   /* priority: INT_MAX >= x >= 0 */
+};
+
+
+
+
+/*!  GPIO functions for PXA3xx
+*/
+// obsolete
+void pxa3xx_gpio_set_rising_edge_detect (int gpio_id, int dir)
+{
+#if 0
+    unsigned  long flags;
+       int gpio = mfp_to_gpio(gpio_id);
+
+//     if (gpio >= GPIO_EXP_START)
+//     {
+//             return 0;
+//     }
+//     spin_lock_irqsave(&gpio_spin_lock, flags);
+       local_irq_save(flags);
+        
+        if ( dir == GPIO_DIR_IN)
+               GCRER(gpio) =1u << (gpio& 0x1f);
+       else
+               GSRER(gpio) =1u << (gpio& 0x1f);
+       local_irq_restore(flags);
+#endif
+}
+
+void pxa3xx_gpio_set_direction(int gpio_id , int dir)
+{
+#if 0
+    unsigned long flags;
+       int gpio = mfp_to_gpio(gpio_id);
+
+       local_irq_save(flags);
+        
+        if ( dir == GPIO_DIR_IN)
+               GCDR(gpio) =1u << (gpio& 0x1f);
+       else
+               GSDR(gpio) =1u << (gpio& 0x1f);
+       local_irq_restore(flags);
+#endif
+}
+//////////////////////////////////////////////////////////
+
+/* physical layer variables */
+/*! global bus data */
+struct spiphy_dev_s {
+       //struct ssp_dev sspdev;        /*!< ssp port configuration */
+       struct completion transfer_in_process;
+    struct spi_device *Smsdevice; 
+       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;
+};
+
+
+
+
+/*!
+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(struct spiphy_dev_s *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)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+    
+       u_irq_count ++;
+    
+//     PDEBUG("INT counter = %d\n", u_irq_count);
+       printk("cmmb siano 1186 int\n");
+        sms_info("spibus_interrupt %d\n", u_irq_count);
+    
+       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
+*/
+
+//extern dma_addr_t common_buf_end ;
+
+static void spibus_dma_handler(int channel, void *context)
+{
+#if 0
+    struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+//     printk( "recieved interrupt from dma channel %d irq status %x.\n",
+//            channel, irq_status);
+       if (irq_status & DCSR_BUSERR) {
+               printk(KERN_EMERG "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);
+#endif   
+}
+
+void smsspibus_xfer(void *context, unsigned char *txbuf,
+                   unsigned long txbuf_phy_addr, unsigned char *rxbuf,
+                   unsigned long rxbuf_phy_addr, int len)
+{
+    struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+    unsigned char *temp = NULL;
+    int ret;
+
+    //sms_debug(KERN_INFO "smsspibus_xfer \n");
+
+    if(txbuf)
+    {
+       sms_debug("tx_buf:%x,%x,%x,%x,%x,%x", txbuf[0], txbuf[1], txbuf[2], txbuf[3], txbuf[4],txbuf[5]);
+
+       ret = spi_write(spiphy_dev->Smsdevice, txbuf, len);
+
+
+    }
+     
+    //if (ret)
+    //    sms_err(KERN_INFO "smsspibus_xfer spi write ret=0x%x\n",ret);
+
+    //memset (rxbuf, 0xff, 256);
+    if ((rxbuf)&&(len != 16))
+        ret = spi_read(spiphy_dev->Smsdevice, rxbuf, len);
+    
+      sms_debug("rxbuf 4, 5,6,7,8,9=%x,%x,%x,%x,%x,%x\n",rxbuf[4],rxbuf[5],rxbuf[6],rxbuf[7],rxbuf[8],rxbuf[9]);
+      //sms_debug("sms spi read buf=0x%x\n",rxbuf[5]);
+
+}
+
+void smschipreset(void *context)
+{
+
+}
+
+static struct ssp_state  sms_ssp_state ;
+
+void smsspibus_ssp_suspend(void* context )
+{
+    struct spiphy_dev_s *spiphy_dev ;
+    printk("entering smsspibus_ssp_suspend\n");
+    if(!context)
+    {
+        PERROR("smsspibus_ssp_suspend context NULL \n") ;
+        return ;
+    }
+    spiphy_dev = (struct spiphy_dev_s *) context;
+
+    //ssp_flush(&(spiphy_dev->sspdev)) ;
+    //ssp_save_state(&(spiphy_dev->sspdev) , &sms_ssp_state) ;
+    //ssp_disable(&(spiphy_dev->sspdev));
+    //ssp_exit(&spiphy_dev->sspdev);
+    free_irq(gpio_to_irq(CMMB_1186_SPIIRQ), spiphy_dev);
+
+    /*  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);
+       chip_powerdown();
+    
+}
+static void chip_poweron()
+{
+#if 0    
+#ifdef CONFIG_MACH_LC6830_PHONE_BOARD_1_0
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 1);
+       mdelay(100);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 1);
+       mdelay(1);
+#elif defined CONFIG_MACH_LC6830_PHONE_BOARD_1_1
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 1);
+       mdelay(50);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO8), 1);
+       mdelay(200);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 1);
+       mdelay(1);
+#endif
+#else
+
+#endif
+
+//1186 cmmb power on
+
+
+       gpio_direction_output(CMMB_1186_POWER_RESET,0);
+       gpio_direction_output(CMMB_1186_POWER_DOWN,0);
+
+       gpio_direction_output(CMMB_1186_POWER_ENABLE,0);
+       mdelay(100);
+       gpio_direction_output(CMMB_1186_POWER_ENABLE,1);
+       mdelay(100);
+
+       gpio_direction_output(CMMB_1186_POWER_DOWN,1);
+       mdelay(100);
+       gpio_direction_output(CMMB_1186_POWER_RESET,1);
+       mdelay(200);
+
+       printk("cmmb chip_poweron !!!!\n");
+
+}
+
+static void chip_powerdown()
+{
+#if 0    //hzb test
+#ifdef CONFIG_MACH_LC6830_PHONE_BOARD_1_0
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 0);
+       mdelay(50);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 0);
+#elif defined CONFIG_MACH_LC6830_PHONE_BOARD_1_1
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 0);
+       mdelay(100);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO8), 0);
+       mdelay(100);
+       gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 0);
+       mdelay(1);
+#endif
+#else
+
+
+#endif
+
+//1186 cmmb power down
+#if 1
+       gpio_direction_output(CMMB_1186_POWER_ENABLE,0);
+
+       printk("cmmb chip_powerdown !!!!\n");
+
+#endif
+//for test
+       //chip_poweron();
+}
+
+int smsspibus_ssp_resume(void* context) 
+{
+    int ret;
+    struct spiphy_dev_s *spiphy_dev ;
+    u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+    printk("entering smsspibus_ssp_resume\n");
+
+    if(!context){
+        PERROR("smsspibus_ssp_resume context NULL \n");
+        return -1;
+    }
+    spiphy_dev = (struct spiphy_dev_s *) context;
+    chip_poweron();
+    free_irq(gpio_to_irq(CMMB_1186_SPIIRQ), spiphy_dev);
+    //printk("siano 1186 request irq\n");
+    gpio_pull_updown(CMMB_1186_SPIIRQ,GPIOPullDown);
+    //ret = request_gpio_irq(CMMB_1186_SPIIRQ, (pFunc)spibus_interrupt, GPIOEdgelRising, spiphy_dev);       
+    request_irq(gpio_to_irq(CMMB_1186_SPIIRQ),spibus_interrupt,IRQF_TRIGGER_RISING,NULL,spiphy_dev);
+    if(ret<0){
+        printk("siano1186 request irq failed !!\n");
+        ret = -EBUSY;
+        goto fail1;
+    }
+    return 0 ;
+fail1:
+       free_irq(CMMB_1186_SPIIRQ,NULL);
+    return -1 ;
+}
+
+
+
+void *smsspiphy_init(void *context, void (*smsspi_interruptHandler)(void *),void *intr_context)
+{
+
+       int ret;
+       struct spiphy_dev_s *spiphy_dev;
+       u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+       int error;
+
+    sms_debug("smsspiphy_init\n");
+   
+       spiphy_dev = kmalloc(sizeof(struct spiphy_dev_s), GFP_KERNEL);
+    if(!spiphy_dev )
+    {
+        printk("spiphy_dev is null in smsspiphy_init\n") ;
+        return NULL;
+       }
+//zyc , requst gpio
+       //request_cmmb_gpio();
+       chip_powerdown();
+       spiphy_dev->interruptHandler = smsspi_interruptHandler;
+       spiphy_dev->intr_context = intr_context;
+        spiphy_dev->Smsdevice = (struct spi_device*)context;
+    
+    //gpio_pull_updown(CMMB_1186_SPIIRQ, IRQT_FALLING);
+       error = gpio_request(CMMB_1186_SPIIRQ,"cmmb irq");
+       if (error) {
+               //dev_err(&pdev->dev, "failed to request play key gpio\n");
+               //goto free_gpio;
+               printk("gpio request error\n");
+       }
+
+#if 0
+       gpio_direction_output(CMMB_1186_SPIIRQ,1);
+
+       printk("CMMB_1186_SPIIRQ !!!!\n");
+      mdelay(10000);
+       gpio_direction_output(CMMB_1186_SPIIRQ,0);
+       mdelay(10000);
+#endif
+
+    //ret = request_gpio_irq(CMMB_1186_SPIIRQ, spibus_interrupt, GPIOEdgelRising, spiphy_dev);//
+    gpio_pull_updown(CMMB_1186_SPIIRQ,GPIOPullUp);
+    //ret = request_gpio_irq(CMMB_1186_SPIIRQ, (pFunc)spibus_interrupt, GPIOEdgelRising, spiphy_dev);       
+    request_irq(gpio_to_irq(CMMB_1186_SPIIRQ),spibus_interrupt,IRQF_TRIGGER_RISING,NULL,spiphy_dev);
+
+    if(ret<0){
+        printk("siano 1186 request irq failed !!\n");
+        ret = -EBUSY;
+        goto fail1;
+    }
+    
+    atomic_notifier_chain_register(&panic_notifier_list,&sms_panic_notifier);
+    //panic_sspdev =  &(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");
+       printk("exiting on error\n");
+fail1:
+    free_irq(CMMB_1186_SPIIRQ,NULL);
+       return 0;
+
+}
+
+int smsspiphy_deinit(void *context)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       PDEBUG("entering\n");
+
+       printk("entering smsspiphy_deinit\n");
+
+        panic_sspdev = NULL;
+        atomic_notifier_chain_unregister(&panic_notifier_list,
+                                                &sms_panic_notifier);
+        chip_powerdown();
+       PDEBUG("exiting\n");
+       return 0;
+}
+
+void smsspiphy_set_config(struct spiphy_dev_s *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 = SPI_RX_FIFO_RFT |SPI_TX_FIFO_TFT | 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)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       smsspiphy_set_config(spiphy_dev, 3);
+       msleep(100);
+}
+
+void fwDnlComplete(void *context, int App)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       smsspiphy_set_config(spiphy_dev, 1);
+       msleep(100);
+}