--- /dev/null
+
+ menu "CMMB"
+ config CMMB
+-tristate "ROCKCHIP CMMB"
+ >---default y
+ >---help
+ rk28 cmmb module.
+ ----------
+
+ source "drivers/cmmb/siano/Kconfig"
+ endmenu
--- /dev/null
+#
+# 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/
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+/*
+ *
+ * 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);
--- /dev/null
+/*
+ *
+ * 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_ */
--- /dev/null
+#
+# 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
--- /dev/null
+###############################################################################
+#
+# 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
+
+
+
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/****************************************************************
+
+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, ¶ms, &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");
+}
--- /dev/null
+/****************************************************************
+
+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__ */
--- /dev/null
+/****************************************************************
+
+ 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(¬ifyee->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(¬ifyee->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(¬ifyee->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");
--- /dev/null
+/****************************************************************
+
+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__ */
--- /dev/null
+/****************************************************************
+
+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_*/
--- /dev/null
+/****************************************************************
+
+ 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 */
+}
+
--- /dev/null
+/****************************************************************
+
+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__ */
+
--- /dev/null
+/****************************************************************
+
+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;
+}
--- /dev/null
+/****************************************************************
+
+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_*/
--- /dev/null
+/****************************************************************
+
+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(¶ms, 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(¶ms, &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");
+}
--- /dev/null
+/****************************************************************
+
+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__ */
--- /dev/null
+/****************************************************************
+
+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);
+}
--- /dev/null
+/****************************************************************
+
+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);
+}