From 6d6d261f6d416947f9c17492067a2f76c414d6cb Mon Sep 17 00:00:00 2001 From: zyc Date: Sat, 21 Aug 2010 14:47:45 +0800 Subject: [PATCH] add cmmb moudle file directory. --- drivers/cmmb/Kconfig | 11 + drivers/cmmb/Makefile | 9 + drivers/cmmb/cmmb_class.c | 231 ++++ drivers/cmmb/cmmb_class.h | 57 + drivers/cmmb/cmmb_memory.c | 499 +++++++ drivers/cmmb/cmmb_memory.h | 64 + drivers/cmmb/cmmb_ringbuffer.c | 163 +++ drivers/cmmb/cmmb_ringbuffer.h | 138 ++ drivers/cmmb/siano/Kconfig | 72 + drivers/cmmb/siano/Makefile | 102 ++ drivers/cmmb/siano/compat.h | 238 ++++ drivers/cmmb/siano/sms-cards.c | 329 +++++ drivers/cmmb/siano/sms-cards.h | 105 ++ drivers/cmmb/siano/smschar.c | 808 +++++++++++ drivers/cmmb/siano/smscharioctl.h | 55 + drivers/cmmb/siano/smscoreapi.c | 2015 ++++++++++++++++++++++++++++ drivers/cmmb/siano/smscoreapi.h | 547 ++++++++ drivers/cmmb/siano/smsdbg_prn.h | 63 + drivers/cmmb/siano/smsendian.c | 100 ++ drivers/cmmb/siano/smsendian.h | 32 + drivers/cmmb/siano/smsspicommon.c | 439 ++++++ drivers/cmmb/siano/smsspicommon.h | 96 ++ drivers/cmmb/siano/smsspilog.c | 625 +++++++++ drivers/cmmb/siano/smsspiphy.h | 38 + drivers/cmmb/siano/smsspiphy_pxa.c | 732 ++++++++++ drivers/cmmb/siano/smsspiphy_rk.c | 631 +++++++++ 26 files changed, 8199 insertions(+) create mode 100755 drivers/cmmb/Kconfig create mode 100755 drivers/cmmb/Makefile create mode 100755 drivers/cmmb/cmmb_class.c create mode 100755 drivers/cmmb/cmmb_class.h create mode 100755 drivers/cmmb/cmmb_memory.c create mode 100755 drivers/cmmb/cmmb_memory.h create mode 100755 drivers/cmmb/cmmb_ringbuffer.c create mode 100755 drivers/cmmb/cmmb_ringbuffer.h create mode 100755 drivers/cmmb/siano/Kconfig create mode 100755 drivers/cmmb/siano/Makefile create mode 100755 drivers/cmmb/siano/compat.h create mode 100755 drivers/cmmb/siano/sms-cards.c create mode 100755 drivers/cmmb/siano/sms-cards.h create mode 100755 drivers/cmmb/siano/smschar.c create mode 100755 drivers/cmmb/siano/smscharioctl.h create mode 100755 drivers/cmmb/siano/smscoreapi.c create mode 100755 drivers/cmmb/siano/smscoreapi.h create mode 100755 drivers/cmmb/siano/smsdbg_prn.h create mode 100755 drivers/cmmb/siano/smsendian.c create mode 100755 drivers/cmmb/siano/smsendian.h create mode 100755 drivers/cmmb/siano/smsspicommon.c create mode 100755 drivers/cmmb/siano/smsspicommon.h create mode 100755 drivers/cmmb/siano/smsspilog.c create mode 100755 drivers/cmmb/siano/smsspiphy.h create mode 100755 drivers/cmmb/siano/smsspiphy_pxa.c create mode 100755 drivers/cmmb/siano/smsspiphy_rk.c diff --git a/drivers/cmmb/Kconfig b/drivers/cmmb/Kconfig new file mode 100755 index 000000000000..9df2cd23da80 --- /dev/null +++ b/drivers/cmmb/Kconfig @@ -0,0 +1,11 @@ + + menu "CMMB" + config CMMB +-tristate "ROCKCHIP CMMB" + >---default y + >---help + rk28 cmmb module. + ---------- + + source "drivers/cmmb/siano/Kconfig" + endmenu diff --git a/drivers/cmmb/Makefile b/drivers/cmmb/Makefile new file mode 100755 index 000000000000..e32d38451987 --- /dev/null +++ b/drivers/cmmb/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the dsp core. +# + +obj-$(CONFIG_CMMB) += cmmb_ringbuffer.o +obj-$(CONFIG_CMMB) += cmmb_class.o +obj-$(CONFIG_CMMB) += cmmb_memory.o + +obj-$(CONFIG_CMMB) += siano/ diff --git a/drivers/cmmb/cmmb_class.c b/drivers/cmmb/cmmb_class.c new file mode 100755 index 000000000000..2c7d99bd0ee4 --- /dev/null +++ b/drivers/cmmb/cmmb_class.c @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cmmb_class.h" + + +#if 1 +#define DBGERR(fmt...) printk(KERN_DEBUG fmt) +#else +#define DBGERR(fmt...) +#endif + +#if 0 +#define DBG(fmt...) printk(KERN_DEBUG fmt) +#else +#define DBG(fmt...) +#endif + +#define MAX_CMMB_ADAPTER 2 +#define MAX_CMMB_MINORS (MAX_CMMB_ADAPTER*4) + + +struct cmmb_adapter CMMB_adapter; +struct class * cmmb_class; + +static struct cdev cmmb_device_cdev; + +static int cmmb_device_open(struct inode *inode, struct file *file); + +static struct file_operations cmmb_device_fops = +{ + .owner = THIS_MODULE, + .open = cmmb_device_open +}; + +static struct cmmb_device* cmmb_find_device (int minor) +{ + + struct cmmb_device *dev; + DBG("[CMMB HW]:[class]:enter cmmb_find_device\n"); + + list_for_each_entry(dev, &CMMB_adapter.device_list, list_head) + if (dev->type == minor) + return dev; + + return NULL; +} + +static int cmmb_device_open(struct inode *inode, struct file *file) +{ + struct cmmb_device *cmmbdev; + + DBG("[CMMB HW]:[class]:enter cmmb_device_open\n"); + + cmmbdev = cmmb_find_device (iminor(inode)); + + DBG("[CMMB HW]:[class]:cmmbdev.type%d\n",cmmbdev->type); + + if (cmmbdev && cmmbdev->fops) { + int err = 0; + const struct file_operations *old_fops; + + file->private_data = cmmbdev; + old_fops = file->f_op; + file->f_op = fops_get(cmmbdev->fops); + if(file->f_op->open) + err = file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + return err; + } + return -ENODEV; +} + + +static int cmmb_register_adapter(const char *name, struct device *device) +{ + DBG("[CMMB HW]:[class]:cmmb_register_adapter\n"); + + memset (&CMMB_adapter, 0, sizeof(struct cmmb_adapter)); + + INIT_LIST_HEAD (&CMMB_adapter.device_list); + + CMMB_adapter.num = 0; + CMMB_adapter.name = name; + CMMB_adapter.device = device; + + return 0; +} + + +static int cmmb_unregister_adapter(struct cmmb_adapter *adap) +{ + DBG("[CMMB HW]:[class]:cmmb_unregister_adapter\n"); + + memset (&CMMB_adapter, 0, sizeof(struct cmmb_adapter)); + + return 0; +} + + +int cmmb_register_device(struct cmmb_adapter *adap, struct cmmb_device **pcmmbdev, + struct file_operations *fops, void *priv, int type,char* name) +{ + struct cmmb_device *cmmbdev; + struct file_operations *cmmbdevfops; + struct device *clsdev; + + DBG("[CMMB HW]:[class]:cmmb_register_device\n"); + + *pcmmbdev = cmmbdev = kmalloc(sizeof(struct cmmb_device), GFP_KERNEL); + if(!pcmmbdev) + { + DBGERR("[CMMB HW]:[class]:[err]: cmmb register device cmmbdev malloc fail!!!\n"); + return -ENOMEM; + } + + cmmbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); + + if (!cmmbdevfops){ + DBGERR("[CMMB HW]:[class]:[err]: cmmb register device cmmbdevfops malloc fail!!!\n"); + kfree (cmmbdev); + return -ENOMEM; + } + + cmmbdev->type = type; + cmmbdev->adapter = adap; + cmmbdev->priv = priv; + cmmbdev->fops = cmmbdevfops; + + init_waitqueue_head (&cmmbdev->wait_queue); + + memcpy(cmmbdev->fops, fops, sizeof(struct file_operations)); + cmmbdev->fops->owner = THIS_MODULE; + + list_add_tail (&cmmbdev->list_head, &adap->device_list); + + clsdev = device_create(cmmb_class, adap->device,MKDEV(CMMB_MAJOR, type),NULL,name); + if (IS_ERR(clsdev)) { + DBGERR("[CMMB HW]:[class]:[err]: creat dev fail!!!\n"); + return PTR_ERR(clsdev); + } + + return 0; +} +EXPORT_SYMBOL(cmmb_register_device); + + +void cmmb_unregister_device(struct cmmb_device *cmmbdev) +{ + if (!cmmbdev) + return; + + DBG("[CMMB HW]:[class]:cmmb_unregister_device\n"); + + device_destroy(cmmb_class, MKDEV(CMMB_MAJOR, cmmbdev->type)); + + list_del (&cmmbdev->list_head); + kfree (cmmbdev->fops); + kfree (cmmbdev); +} +EXPORT_SYMBOL(cmmb_unregister_device); + +static int __init init_cmmbclass(void) +{ + int retval; + struct cmmb_adapter* cmmbadapter; + struct cmmb_device * tunerdev; + dev_t dev = MKDEV(CMMB_MAJOR, 0); + + DBG("[CMMB HW]:[class]: init_cmmbclass\n"); + + if ((retval = register_chrdev_region(dev, CMMB_MAJOR, "CMMB")) != 0){ + DBGERR("[CMMB HW]:[class]:[err]: register chrdev fail!!!\n"); + return retval; + } + + cdev_init(&cmmb_device_cdev, &cmmb_device_fops); + if ((retval = cdev_add(&cmmb_device_cdev, dev, MAX_CMMB_MINORS)) != 0){ + DBGERR("[CMMB HW]:[class]:[err]: cedv add fail!!!\n"); + goto error; + } + + cmmb_class = class_create(THIS_MODULE, "cmmb"); + if (IS_ERR(cmmb_class)) { + DBGERR("[CMMB HW]:[class]:[err]: class creat fail!!!\n"); + retval = PTR_ERR(cmmb_class); + goto error; + } + + cmmb_register_adapter("cmmb_adapter", NULL); + + return 0; + +error: + cdev_del(&cmmb_device_cdev); + unregister_chrdev_region(dev, MAX_CMMB_MINORS); + return retval; +} + + +static void __exit exit_cmmbclass(void) +{ + DBG("[CMMB HW]:[class]: exit_cmmbclass\n"); + + class_destroy(cmmb_class); + cdev_del(&cmmb_device_cdev); + cmmb_unregister_adapter(&CMMB_adapter); + unregister_chrdev_region(MKDEV(CMMB_MAJOR, 0), MAX_CMMB_MINORS); +} + + +subsys_initcall(init_cmmbclass); +module_exit(exit_cmmbclass); + +MODULE_DESCRIPTION("CMMB CORE"); +MODULE_AUTHOR("HT,HZB,HH,LW"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/cmmb/cmmb_class.h b/drivers/cmmb/cmmb_class.h new file mode 100755 index 000000000000..3294f55ff520 --- /dev/null +++ b/drivers/cmmb/cmmb_class.h @@ -0,0 +1,57 @@ +#ifndef _CMMB_CLASS_H_ +#define _CMMB_CLASS_H_ + + +#include +#include +#include +#include +#include + +#define CMMB_MAJOR 200 + + +#define CMMB_DEVICE_TUNER 0 +#define CMMB_DEVICE_DEMO 1 +#define CMMB_DEVICE_DEMUX 2 +#define CMMB_DEVICE_CA 3 +#define CMMB_DEVICE_MEMO 4 + +extern struct class * cmmb_class; + +struct cmmb_adapter { + int num; + struct list_head list_head; + struct list_head device_list; + const char *name; + void* priv; + struct device *device; +}; + + +extern struct cmmb_adapter CMMB_adapter; +struct cmmb_device { + struct list_head list_head; + struct file_operations *fops; + struct cmmb_adapter *adapter; + int type; + u32 id; + + wait_queue_head_t wait_queue; + + int (*kernel_ioctl)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); + + void *priv; +}; + + +int cmmb_register_device(struct cmmb_adapter *adap, struct cmmb_device **pcmmbdev, + struct file_operations *fops, void *priv, int type,char* name); +void cmmb_unregister_device(struct cmmb_device *cmmbdev); + +#define cmmb_attach(FUNCTION, ARGS...) ({ \ + FUNCTION(ARGS); \ + + +#endif/* #ifndef _CMMB_CLASS_H_ */ \ No newline at end of file diff --git a/drivers/cmmb/cmmb_memory.c b/drivers/cmmb/cmmb_memory.c new file mode 100755 index 000000000000..f476877b877e --- /dev/null +++ b/drivers/cmmb/cmmb_memory.c @@ -0,0 +1,499 @@ +#include "cmmb_memory.h" +#include "cmmb_class.h" +#include +#include +#include + +#if 1 +#define DBGERR(x...) printk(KERN_INFO x) +#else +#define DBGERR(x...) +#endif + +#if 0 +#define DBG(x...) printk(KERN_INFO x) +#else +#define DBG(x...) +#endif + +struct cmmb_memory CMMB_memo; +static struct cmmb_device* cmmbmemo; + + +static int cmmbmemo_release(struct inode *inode, struct file *file) +{ + struct cmmb_memory *cmmb_memo = (struct cmmb_memory*)file->private_data; + + DBG("[CMMB HW]:[memory]: enter cmmb av memory release\n"); + + mutex_lock(&cmmb_memo->mutex); + + cmmb_memo->usr--; + + if(cmmb_memo->usr == 0){ + kfree(cmmb_memo->video_buf); + kfree(cmmb_memo->audio_buf); + kfree(cmmb_memo->data_buf); + mutex_unlock(&cmmb_memo->mutex); + DBG("[CMMB HW]:[memory]: enter cmmb av memory release free buffer\n"); + } else{ + mutex_unlock(&cmmb_memo->mutex); + } + return 0; +} + +//hzb@20100416,ÔÚ´ò¿ªÉ豸µÄʱºòÉêÇë¿Õ¼ä +static int cmmbmemo_open(struct inode * inode, struct file * file) +{ + struct cmmb_memory *cmmbmemo = &CMMB_memo; + int ret = 0; + + DBG("[CMMB HW]:[memory]: enter cmmb memo open\n"); + + if (mutex_lock_interruptible(&cmmbmemo->mutex)) + return -ERESTARTSYS; + + cmmbmemo->usr++; + + if (cmmbmemo->usr == 1) + { + DBG("[CMMB HW]:[memory]:cmmb video buffer malloc\n"); + + cmmbmemo->video_buf = NULL; + cmmbmemo->audio_buf = NULL; + cmmbmemo->data_buf = NULL; + + cmmbmemo->video_buf = kmalloc(CMMB_VIDEO_BUFFER_SIZE+1, GFP_KERNEL); + + if (cmmbmemo->video_buf == NULL){ + ret = - ENOMEM; + DBGERR("[CMMB HW]:[memory]:[err]: cmmb video buffer malloc fail!!!\n"); + goto kmalloc_fail; + } + + cmmbmemo->audio_buf = kmalloc(CMMB_AUDIO_BUFFER_SIZE+1, GFP_KERNEL); + + if (cmmbmemo->audio_buf == NULL){ + ret = - ENOMEM; + DBGERR("[CMMB HW]:[memory]:[err]: cmmb audio buffer malloc fail!!!\n"); + goto kmalloc_fail; + } + + cmmbmemo->data_buf = kmalloc(1, GFP_KERNEL); + + if (cmmbmemo->data_buf == NULL){ + ret = - ENOMEM; + DBGERR("[CMMB HW]:[memory]:[err]: cmmb data buffer malloc fail!!!\n"); + goto kmalloc_fail; + } + + //hzb@20100415,init av ring buffers,cmmb need three ring buffers to store the demuxed data + cmmb_ringbuffer_init(&cmmbmemo->buffer_Video, cmmbmemo->video_buf, CMMB_VIDEO_BUFFER_SIZE); //init video ring buffer + cmmb_ringbuffer_init(&cmmbmemo->buffer_Audio, cmmbmemo->audio_buf, CMMB_AUDIO_BUFFER_SIZE); //init audio ring buffer + cmmb_ringbuffer_init(&cmmbmemo->buffer_Data, cmmbmemo->data_buf, 1); //init data ring buffer + + cmmbmemo->w_datatype = CMMB_NULL_TYPE; + cmmbmemo->r_datatype = CMMB_NULL_TYPE; + } + file->private_data = cmmbmemo; //hzb@20100415,store the cmmbmemo struct in the file private data + mutex_unlock(&cmmbmemo->mutex); + return ret; + +kmalloc_fail: + kfree(cmmbmemo->video_buf); + kfree(cmmbmemo->audio_buf); + kfree(cmmbmemo->data_buf); + mutex_unlock(&cmmbmemo->mutex); + return ret; +} + + +static ssize_t cmmbmemo_read(struct file *file, char __user *buf, size_t count,loff_t *ppos) +{ + struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data; + ssize_t avail_V, avail_A, avail_D; + ssize_t ret; + + DBG("[CMMB HW]:[memory]:enter cmmb memory read\n"); + + if (cmmbmemo->r_datatype == CMMB_VIDEO_TYPE){ +#if 0 + DECLARE_WAITQUEUE(wait, current); + for(;;){ + avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video); + + if (avail_V < count){ + add_wait_queue(&cmmbmemo->buffer_Video.queue, &wait); + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + remove_wait_queue(&cmmbmemo->buffer_Video.queue, &wait); + if (signal_pending(current)){ + ret = -ERESTARTSYS; + goto out2; + } + } + } +#else +#if 0 + avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video); + while (avail_V < count){ + DBG("[CMMB HW]:[memory]:cmmb memory read video data sleep!!\n"); + spin_lock(cmmbmemo->buffer_Video.lock); + cmmbmemo->buffer_Video.condition = 0; + spin_unlock(cmmbmemo->buffer_Video.lock); + if (wait_event_interruptible(cmmbmemo->buffer_Video.queue, cmmbmemo->buffer_Video.condition)) + return -ERESTARTSYS; + + avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video); + DBG("[CMMB HW]:[memory]:cmmb memory read video data awake\n"); + } +#endif + avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video); + if (avail_V < count) + return 0; +#endif + ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Video, buf, count, 1); + + DBG("[CMMB HW]:[memory]:cmmb memory video read ret = 0x%x\n",ret); + }else if (cmmbmemo->r_datatype == CMMB_AUDIO_TYPE){ +#if 0 + DECLARE_WAITQUEUE(wait, current); + for(;;){ + avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio); + if (avail_A < count){ + add_wait_queue(&cmmbmemo->buffer_Audio.queue, &wait); + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + remove_wait_queue(&cmmbmemo->buffer_Audio.queue, &wait); + if (signal_pending(current)){ + ret = -ERESTARTSYS; + goto out2; + } + } + } +#else +#if 0 + avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio); + while (avail_A < count){ + DBG("[CMMB HW]:[memory]:cmmb memory read audio data sleep!!\n"); + spin_lock(cmmbmemo->buffer_Audio.lock); + cmmbmemo->buffer_Audio.condition = 0; + spin_unlock(cmmbmemo->buffer_Audio.lock); + if (wait_event_interruptible(cmmbmemo->buffer_Audio.queue, cmmbmemo->buffer_Audio.condition)) + return -ERESTARTSYS; + + avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio); + DBG("[CMMB HW]:[memory]:cmmb memory read audio data awake\n"); + } +#endif + avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio); + if (avail_A < count) + return 0; +#endif + ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Audio, buf, count, 1); + }else if(cmmbmemo->r_datatype == CMMB_DATA_TYPE){ + #if 0 + DECLARE_WAITQUEUE(wait, current); + for(;;){ + avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data); + if (avail_D < count){ + add_wait_queue(&cmmbmemo->buffer_Data.queue, &wait); + __set_current_state(TASK_INTERRUPTIBLE); + schedule(); + remove_wait_queue(&cmmbmemo->buffer_Data.queue, &wait); + if (signal_pending(current)){ + ret = -ERESTARTSYS; + goto out2; + } + } + } +#else +#if 0 + avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data); + while (avail_D < count){ + DBG("[CMMB HW]:[memory]:cmmb memory read data sleep!!\n"); + spin_lock(cmmbmemo->buffer_Data.lock); + cmmbmemo->buffer_Data.condition = 0; + spin_unlock(cmmbmemo->buffer_Data.lock); + if (wait_event_interruptible(cmmbmemo->buffer_Data.queue, cmmbmemo->buffer_Data.condition)) + return -ERESTARTSYS; + + avail_D= cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data); + DBG("[CMMB HW]:[memory]:cmmb memory read data awake\n"); + } +#endif + avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data); + if (avail_D < count) + return 0; +#endif + ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Data, buf, count, 1); + } + +out2: + cmmbmemo->r_datatype = CMMB_NULL_TYPE; + return ret;; +} + + + +static ssize_t cmmbmemo_write(struct file *file, char __user *buf, size_t count,loff_t *ppos) +{ + struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data; + ssize_t free_V, free_A, free_D; + ssize_t ret; + static int loop = 0; + + DBG("[CMMB HW]:[memory]:enter cmmbdemux_write\n"); + + if (cmmbmemo->w_datatype == CMMB_VIDEO_TYPE){ + + free_V = cmmb_ringbuffer_free(&cmmbmemo->buffer_Video); + if (free_V >= count){ + ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Video, buf, count); + } + //cmmbmemo->w_datatype = CMMB_NULL_TYPE; + spin_lock(cmmbmemo->buffer_Video.lock); + cmmbmemo->buffer_Video.condition = 1; + spin_unlock(cmmbmemo->buffer_Video.lock); + wake_up_interruptible(&cmmbmemo->buffer_Video.queue); + }else if (cmmbmemo->w_datatype == CMMB_AUDIO_TYPE){ + free_A = cmmb_ringbuffer_free(&cmmbmemo->buffer_Audio); + if (free_A >= count){ + ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Audio, buf, count); + } + //cmmbmemo->w_datatype = CMMB_NULL_TYPE; + spin_lock(cmmbmemo->buffer_Audio.lock); + cmmbmemo->buffer_Audio.condition = 1; + spin_unlock(cmmbmemo->buffer_Audio.lock); + wake_up_interruptible(&cmmbmemo->buffer_Audio.queue); + }else if(cmmbmemo->w_datatype == CMMB_DATA_TYPE){ + free_D = cmmb_ringbuffer_free(&cmmbmemo->buffer_Data); + if (free_D >= count){ + ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Data, buf, count); + } + //cmmbmemo->w_datatype = CMMB_NULL_TYPE; + spin_lock(cmmbmemo->buffer_Data.lock); + cmmbmemo->buffer_Data.condition = 1; + spin_unlock(cmmbmemo->buffer_Data.lock); + wake_up_interruptible(&cmmbmemo->buffer_Data.queue); + } + + return ret; +} + + +int cmmbmemo_valueinit(struct file *file) +{ + struct cmmb_memory *cmmbmemo = file->private_data; + int ret = 0; + + DBG("[CMMB HW]:[memory]: enter cmmb memo open\n"); + + cmmbmemo->video_buf = NULL; + cmmbmemo->audio_buf = NULL; + cmmbmemo->data_buf = NULL; + + cmmbmemo->video_buf = kzalloc(CMMB_VIDEO_BUFFER_SIZE+1, GFP_KERNEL); + + if (cmmbmemo->video_buf == NULL){ + ret = - ENOMEM; + DBGERR("[CMMB HW]:[memory]:[err]: cmmb video buffer malloc fail!!!\n"); + goto kmalloc_fail; + } + + cmmbmemo->audio_buf = kzalloc(CMMB_AUDIO_BUFFER_SIZE+1, GFP_KERNEL); + + if (cmmbmemo->audio_buf == NULL){ + ret = - ENOMEM; + DBGERR("[CMMB HW]:[memory]:[err]: cmmb audio buffer malloc fail!!!\n"); + goto kmalloc_fail; + } + + cmmbmemo->data_buf = kzalloc(1, GFP_KERNEL); + + if (cmmbmemo->data_buf == NULL){ + ret = - ENOMEM; + DBGERR("[CMMB HW]:[memory]:[err]: cmmb data buffer malloc fail!!!\n"); + goto kmalloc_fail; + } + + //hzb@20100415,init av ring buffers,cmmb need three ring buffers to store the demuxed data + cmmb_ringbuffer_init(&cmmbmemo->buffer_Video, cmmbmemo->video_buf, CMMB_VIDEO_BUFFER_SIZE); //init video ring buffer + cmmb_ringbuffer_init(&cmmbmemo->buffer_Audio, cmmbmemo->audio_buf, CMMB_AUDIO_BUFFER_SIZE); //init audio ring buffer + cmmb_ringbuffer_init(&cmmbmemo->buffer_Data, cmmbmemo->data_buf, 1); //init data ring buffer + + cmmbmemo->w_datatype = CMMB_NULL_TYPE; + cmmbmemo->r_datatype = CMMB_NULL_TYPE; + + return ret; + +kmalloc_fail: + kfree(cmmbmemo->video_buf); + kfree(cmmbmemo->audio_buf); + kfree(cmmbmemo->data_buf); + return ret; +} + +static long cmmbmemo_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data; + long ret = 0; + + DBG("[CMMB HW]:[memory]:enter cmmbdemux_ioctl\n"); + + switch (cmd){ + case CMMB_MEMO_WRITE:{ + cmmbmemo->w_datatype = arg; + } + break; + + case CMMB_MEMO_READ:{ + cmmbmemo->r_datatype = arg; + } + break; + + case CMMB_MEMO_FLUSH_ONE:{ + if (arg == CMMB_VIDEO_TYPE){ + cmmb_ringbuffer_flush(&cmmbmemo->buffer_Video); + }else if (arg == CMMB_AUDIO_TYPE){ + cmmb_ringbuffer_flush(&cmmbmemo->buffer_Audio); + }else if (arg == CMMB_DATA_TYPE){ + cmmb_ringbuffer_flush(&cmmbmemo->buffer_Data); + }else{ + ret = - EINVAL; + } + } + break; + + case CMMB_MEMO_FLUSH_ALL:{ + cmmb_ringbuffer_flush(&cmmbmemo->buffer_Video); + cmmb_ringbuffer_flush(&cmmbmemo->buffer_Audio); + cmmb_ringbuffer_flush(&cmmbmemo->buffer_Data); + } + break; + + case CMMB_MEMO_INIT:{ + return cmmbmemo_valueinit(file); + } + break; + + case CMMB_SET_VIDEO_TYPE:{ + cmmbmemo->videotype = arg; + } + break; + + case CMMB_SET_AUDIO_TYPE:{ + cmmbmemo->audiotype = arg; + } + break; + + case CMMB_SET_AUDIO_SAMPLE:{ + cmmbmemo->audiosample = arg; + } + break; + + case CMMB_GET_VIDEO_TYPE:{ + return cmmbmemo->videotype; + } + break; + + case CMMB_GET_AUDIO_TYPE:{ + return cmmbmemo->videotype; + } + break; + + case CMMB_GET_AUDIO_SAMPLE:{ + return cmmbmemo->audiosample; + } + break; + + case CMMB_GET_BUFF_FREE:{ + if (arg == CMMB_VIDEO_TYPE){ + ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Video); + }else if (arg == CMMB_AUDIO_TYPE){ + ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Audio); + }else if (arg == CMMB_DATA_TYPE){ + ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Data); + }else{ + ret = - EINVAL; + } + } + break; + + case CMMB_GET_BUFF_AVAIL:{ + if (arg == CMMB_VIDEO_TYPE){ + ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video); + }else if (arg == CMMB_AUDIO_TYPE){ + ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio); + }else if (arg == CMMB_DATA_TYPE){ + ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data); + }else{ + ret = - EINVAL; + } + } + break; + + default: + ; + break; + } + return ret; +} + +static unsigned int cmmbmemo_poll(struct file *file, struct poll_table_struct *wait) +{ + struct cmmb_demux *cmmbmemo = (struct cmmb_memory*)file->private_data; + unsigned int mask = 0; + + DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__); + + //2todo memo poll, now doing nothing + + return mask; +} + + +static int cmmbmemo_mmap(struct file *file, struct vm_area_struct *vma) +{ + //2 todo memo mmmap, now doing nothing + DBG("[CMMB HW]:[memory]:enter cmmbdemux_ioctl\n"); + return 0; +} + + +struct file_operations cmmbmemeo_fops = +{ + .open = cmmbmemo_open, + .release = cmmbmemo_release, + .read = cmmbmemo_read, + .write = cmmbmemo_write, + .mmap = cmmbmemo_mmap, + .poll = cmmbmemo_poll, + .unlocked_ioctl = cmmbmemo_ioctl, +}; + +static int __init cmmbmemo_init(void) +{ + int res; + + DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__); + res =cmmb_register_device(&CMMB_adapter,&cmmbmemo, &cmmbmemeo_fops, NULL, CMMB_DEVICE_MEMO,"cmmb_memo"); + mutex_init(&CMMB_memo.mutex); + CMMB_memo.usr = 0; + return res; +} + +static void __exit cmmbmemo_exit(void) +{ + DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__); + cmmb_unregister_device(cmmbmemo); + //mutex_destroy(mutex); +} + +module_init(cmmbmemo_init); +module_exit(cmmbmemo_exit); + +MODULE_DESCRIPTION("CMMB demodulator general driver"); +MODULE_AUTHOR("HT,HZB,HH,LW"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/cmmb/cmmb_memory.h b/drivers/cmmb/cmmb_memory.h new file mode 100755 index 000000000000..efd85ece78ef --- /dev/null +++ b/drivers/cmmb/cmmb_memory.h @@ -0,0 +1,64 @@ +#ifndef _CMMB_AV_MEMORY_H_ +#define _CMMB_AV_MEMORY_H_ + +#include +#include +//#include +#include +#include "cmmb_ringbuffer.h" + + +#define CMMB_MEMO_WRITE (0x80000001) +#define CMMB_MEMO_READ (0x80000002) +#define CMMB_MEMO_FLUSH_ONE (0x80000003) +#define CMMB_MEMO_FLUSH_ALL (0x80000004) +#define CMMB_MEMO_INIT (0x80000005) +#define CMMB_SET_VIDEO_TYPE (0x80000006) +#define CMMB_SET_AUDIO_TYPE (0x80000007) +#define CMMB_SET_AUDIO_SAMPLE (0x80000008) +#define CMMB_GET_VIDEO_TYPE (0x80000009) +#define CMMB_GET_AUDIO_TYPE (0x8000000a) +#define CMMB_GET_AUDIO_SAMPLE (0x8000000b) +#define CMMB_GET_BUFF_FREE (0x8000000c) +#define CMMB_GET_BUFF_AVAIL (0x8000000d) + + +struct cmmb_memory +{ + int w_datatype; + int r_datatype; + unsigned long videotype; + unsigned long audiotype; + unsigned long audiosample; + int usr; + + struct device *device; + struct file_operations* fops; + struct dvb_ringbuffer buffer_Video; + struct dvb_ringbuffer buffer_Audio; + struct dvb_ringbuffer buffer_Data; + u8 *video_buf; + u8 *audio_buf; + u8 *data_buf; + + #define CMMB_VIDEO_TYPE 0 + #define CMMB_AUDIO_TYPE 1 + #define CMMB_DATA_TYPE 2 + #define CMMB_NULL_TYPE 3 + + #define CMMB_VIDEO_BUFFER_SIZE (512*1024) + #define CMMB_AUDIO_BUFFER_SIZE (64*1024) + #define CMMB_DATA_BUFFER_SIZE (1*1024) + + struct mutex mutex; + //struct semaphore sem; + spinlock_t lock; + wait_queue_head_t rqueue; + void* priv; +}; + + + +#endif/*_CMMBMEMORY_H_*/ + + diff --git a/drivers/cmmb/cmmb_ringbuffer.c b/drivers/cmmb/cmmb_ringbuffer.c new file mode 100755 index 000000000000..0f97399f70bb --- /dev/null +++ b/drivers/cmmb/cmmb_ringbuffer.c @@ -0,0 +1,163 @@ +/* + * + * dvb_ringbuffer.c: ring buffer implementation for the dvb driver + * + * Copyright (C) 2003 Oliver Endriss + * Copyright (C) 2004 Andrew de Quincey + * + * based on code originally found in av7110.c & dvb_ci.c: + * Copyright (C) 1999-2003 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + + +#include +#include +#include +#include +#include +#include + +#include "cmmb_ringbuffer.h" + + +void cmmb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) +{ + rbuf->pread=rbuf->pwrite=0; + rbuf->data=data; + rbuf->size=len; + rbuf->error=0; + + init_waitqueue_head(&rbuf->queue); + + spin_lock_init(&(rbuf->lock)); + +} + + + +int cmmb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) +{ + return (rbuf->pread==rbuf->pwrite); +} + + + +ssize_t cmmb_ringbuffer_free(struct dvb_ringbuffer *rbuf) +{ + ssize_t free; + + free = rbuf->pread - rbuf->pwrite; + if (free <= 0) + free += rbuf->size; + return free-1; +} + + + +ssize_t cmmb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) +{ + ssize_t avail; + + avail = rbuf->pwrite - rbuf->pread; + if (avail < 0) + avail += rbuf->size; + return avail; +} + + + +void cmmb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) +{ + rbuf->pread = rbuf->pwrite; + rbuf->error = 0; +} + + + +void cmmb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf) +{ + unsigned long flags; + + spin_lock_irqsave(&rbuf->lock, flags); + cmmb_ringbuffer_flush(rbuf); + spin_unlock_irqrestore(&rbuf->lock, flags); + + wake_up(&rbuf->queue); +} + + + +ssize_t cmmb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem) +{ + size_t todo = len; + size_t split; + + split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; + if (split > 0) { + if (!usermem) + memcpy(buf, rbuf->data+rbuf->pread, split); + else + if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) + return -EFAULT; + buf += split; + todo -= split; + rbuf->pread = 0; + } + if (!usermem) + memcpy(buf, rbuf->data+rbuf->pread, todo); + else + if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) + return -EFAULT; + + rbuf->pread = (rbuf->pread + todo) % rbuf->size; + + return len; +} + + + +ssize_t cmmb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len) +{ + size_t todo = len; + size_t split; + + split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; + + if (split > 0) { + memcpy(rbuf->data+rbuf->pwrite, buf, split); + buf += split; + todo -= split; + rbuf->pwrite = 0; + } + memcpy(rbuf->data+rbuf->pwrite, buf, todo); + rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; + + return len; +} + + + + +EXPORT_SYMBOL(cmmb_ringbuffer_init); +EXPORT_SYMBOL(cmmb_ringbuffer_empty); +EXPORT_SYMBOL(cmmb_ringbuffer_free); +EXPORT_SYMBOL(cmmb_ringbuffer_avail); +EXPORT_SYMBOL(cmmb_ringbuffer_flush_spinlock_wakeup); +EXPORT_SYMBOL(cmmb_ringbuffer_read); +EXPORT_SYMBOL(cmmb_ringbuffer_write); diff --git a/drivers/cmmb/cmmb_ringbuffer.h b/drivers/cmmb/cmmb_ringbuffer.h new file mode 100755 index 000000000000..fea007911ece --- /dev/null +++ b/drivers/cmmb/cmmb_ringbuffer.h @@ -0,0 +1,138 @@ +/* + * + * dvb_ringbuffer.h: ring buffer implementation for the dvb driver + * + * Copyright (C) 2003 Oliver Endriss + * Copyright (C) 2004 Andrew de Quincey + * + * based on code originally found in av7110.c & dvb_ci.c: + * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DVB_RINGBUFFER_H_1 +#define _DVB_RINGBUFFER_H_1 + +#include +#include + +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 bytes *** +** free = dvb_ringbuffer_free(rbuf); +** if (free >= buflen) +** count = dvb_ringbuffer_write(rbuf, buffer, buflen); +** else +** ... +** +** *** read min. 1000, max. 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 in the buffer */ +#define DVB_RINGBUFFER_PEEK(rbuf,offs) \ + (rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size] + +/* advance read ptr by bytes */ +#define DVB_RINGBUFFER_SKIP(rbuf,num) \ + (rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size + +/* +** read bytes from ring buffer into +** specifies whether 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 bytes to ring buffer +** specifies whether 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. + * + * Ringbuffer to write to. + * Buffer to write. + * Length of buffer (currently limited to 65535 bytes max). + * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. + */ + + +#endif /* _DVB_RINGBUFFER_H_ */ diff --git a/drivers/cmmb/siano/Kconfig b/drivers/cmmb/siano/Kconfig new file mode 100755 index 000000000000..7e0071468784 --- /dev/null +++ b/drivers/cmmb/siano/Kconfig @@ -0,0 +1,72 @@ +# +# Siano Mobile Silicon Digital TV device configuration +# + +config SMS_SIANO_MDTV + tristate "Siano SMS1xxx based MDTV receiver" + default y + ---help--- + Choose Y or M here if you have MDTV receiver with a Siano chipset. + + To compile this driver as a module, choose M here + (The modules will be called smsmdtv). + + Note: All dependents, if selected, will be part of this module. + + Further documentation on this driver can be found on the WWW at http://www.siano-ms.com/ + +if SMS_SIANO_MDTV +menu "Siano module components" + +# Kernel sub systems support + +config SMS_DVB3_SUBSYS + bool "DVB v.3 Subsystem support" + default n + ---help--- + Choose if you would like to have DVB v.3 kernel sub-system support. + +config SMS_DVB5_S2API_SUBSYS + bool "DVB v.5 (S2 API) Subsystem support" + default n + ---help--- + Choose if you would like to have DVB v.5 (S2 API) kernel sub-system support. + +config SMS_HOSTLIB_SUBSYS + bool "Host Library Subsystem support" + default y + ---help--- + Choose if you would like to have Siano's host library kernel sub-system support. + +if SMS_HOSTLIB_SUBSYS + +config SMS_NET_SUBSYS + bool "Siano Network Adapter" + default n + ---help--- + Choose if you would like to have Siano's network adapter support. + +endif # SMS_HOSTLIB_SUBSYS + +# Hardware interfaces support + +config SMS_USB_DRV + bool "USB interface support" + default n + ---help--- + Choose if you would like to have Siano's support for USB interface + +config SMS_SDIO_DRV + bool "SDIO interface support" + default n + ---help--- + Choose if you would like to have Siano's support for SDIO interface + +config SMS_SPI_ROCKCHIP + bool "Rockchip SPI interface support" + default y + ---help--- + Choose if you would like to have Siano's support for Rockchip SPI interface + +endmenu +endif # SMS_SIANO_MDTV diff --git a/drivers/cmmb/siano/Makefile b/drivers/cmmb/siano/Makefile new file mode 100755 index 000000000000..7ab5c219bf0b --- /dev/null +++ b/drivers/cmmb/siano/Makefile @@ -0,0 +1,102 @@ +############################################################################### +# +# Siano Mobile Silicon, Inc. +# MDTV receiver kernel modules. +# Copyright (C) 2006-2008, Uri Shkolnik +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################### + + +# Local variables initialization +SMS_DVB3_SUBSYS := 0 +SMS_DVB5_S2API_SUBSYS := 0 +SMS_HOSTLIB_SUBSYS := 0 + +SMS_USB_DRV := 0 +SMS_SDIO_DRV := 0 +SMS_SPI_PXA310_DRV := 0 + + +# Default object, include in every build variant +SMSOBJ := smscoreapi.o sms-cards.o smsendian.o + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) + + +# Kernel subsystems support +ifdef CONFIG_SMS_DVB3_SUBSYS +ifneq ($(CONFIG_SMS_DVB3_SUBSYS),n) +SMS_DVB3_SUBSYS := 1 +EXTRA_CFLAGS += -DSMS_DVB3_SUBSYS -Idrivers/media/dvb/dvb-core +SMSOBJ += smsdvb.o +endif +endif + +ifdef CONFIG_SMS_DVB5_S2API_SUBSYS +ifneq ($(CONFIG_SMS_DVB5_S2API_SUBSYS),n) +SMS_DVB5_S2API_SUBSYS := 1 +EXTRA_CFLAGS += -DSMS_DVB5_S2API_SUBSYS +endif +endif + +ifdef CONFIG_SMS_HOSTLIB_SUBSYS +ifneq ($(CONFIG_SMS_HOSTLIB_SUBSYS),n) +SMS_HOSTLIB_SUBSYS := 1 +EXTRA_CFLAGS += -DSMS_HOSTLIB_SUBSYS +SMSOBJ += smschar.o +endif +endif + +ifdef CONFIG_SMS_NET_SUBSYS +ifneq ($(CONFIG_SMS_NET_SUBSYS),n) +SMS_NET_SUBSYS := 1 +EXTRA_CFLAGS += -DSMS_NET_SUBSYS +SMSOBJ += smsnet.o +endif +endif + +# Hardware (host) interfaces support +ifdef CONFIG_SMS_USB_DRV +ifneq ($(CONFIG_SMS_USB_DRV),n) +SMS_USB_DRV := 1 +EXTRA_CFLAGS += -DSMS_USB_DRV +SMSOBJ += smsusb.o +endif +endif + +ifdef CONFIG_SMS_SDIO_DRV +ifneq ($(CONFIG_SMS_SDIO_DRV),n) +SMS_SDIO_DRV := 1 +EXTRA_CFLAGS += -DSMS_SDIO_DRV +SMSOBJ += smssdio.o +endif +endif + +ifdef CONFIG_SMS_SPI_ROCKCHIP +ifneq ($(CONFIG_SMS_SPI_ROCKCHIP),n) +SMS_SPI_ROCKCHIP := 1 +EXTRA_CFLAGS += -DSMS_SPI_ROCKCHIP +SMSOBJ += smsspilog.o smsspicommon.o smsspiphy_rk.o +endif +endif + +# All selected in one module named smsmdtv +smsmdtv-objs := $(SMSOBJ) + +obj-$(CONFIG_SMS_SIANO_MDTV) := smsmdtv.o + + + diff --git a/drivers/cmmb/siano/compat.h b/drivers/cmmb/siano/compat.h new file mode 100755 index 000000000000..551696082a4b --- /dev/null +++ b/drivers/cmmb/siano/compat.h @@ -0,0 +1,238 @@ +/* + * $Id: compat.h,v 1.44 2006/01/15 09:35:16 mchehab Exp $ + */ + +#ifndef _COMPAT_H +#define _COMPAT_H + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +#define KERN_CONT "" +#endif + +/* To allow I2C compatibility code to work */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +#ifdef CONFIG_PROC_FS +#include +#include +#endif +#endif + +/* To allow alsa code to work */ +#ifdef NEED_SOUND_DRIVER_H +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) +#define set_freezable() +#define cancel_delayed_work_sync cancel_rearming_delayed_work +#endif + +#ifndef __pure +# define __pure __attribute__((pure)) +#endif + +#ifndef I2C_M_IGNORE_NAK +# define I2C_M_IGNORE_NAK 0x1000 +#endif + +/* device_create/destroy added in 2.6.18 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +/* on older kernels, class_device_create will in turn be a compat macro */ +# define device_create(a, b, c, d, e, f, g) class_device_create(a, NULL, c, b, d, e, f, g) +# define device_destroy(a, b) class_device_destroy(a, b) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#define IRQF_SHARED SA_SHIRQ +#define IRQF_DISABLED SA_INTERRUPT +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +# define PCIAGP_FAIL 0 + +#define vmalloc_32_user(a) vmalloc_32(a) + +#endif + +/* bool type and enum-based definition of true and false was added in 2.6.19 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +typedef int bool; +#define true 1 +#define false 0 +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) +#define sony_pic_camera_command(a,b) sonypi_camera_command(a,b) + +#define SONY_PIC_COMMAND_SETCAMERAAGC SONYPI_COMMAND_SETCAMERAAGC +#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS SONYPI_COMMAND_SETCAMERABRIGHTNESS +#define SONY_PIC_COMMAND_SETCAMERACOLOR SONYPI_COMMAND_SETCAMERACOLOR +#define SONY_PIC_COMMAND_SETCAMERACONTRAST SONYPI_COMMAND_SETCAMERACONTRAST +#define SONY_PIC_COMMAND_SETCAMERAHUE SONYPI_COMMAND_SETCAMERAHUE +#define SONY_PIC_COMMAND_SETCAMERAPICTURE SONYPI_COMMAND_SETCAMERAPICTURE +#define SONY_PIC_COMMAND_SETCAMERASHARPNESS SONYPI_COMMAND_SETCAMERASHARPNESS +#define SONY_PIC_COMMAND_SETCAMERA SONYPI_COMMAND_SETCAMERA +#endif + +/* pci_dev got a new revision field in 2.6.23-rc1 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) && defined(LINUX_PCI_H) +/* Just make it easier to subsitute pci_dev->revision with + * v4l_compat_pci_rev(pci_dev). It's too bad there isn't some kind of context + * sensitive macro in C that could do this for us. */ +static inline u8 v4l_compat_pci_rev(struct pci_dev *pci) +{ u8 rev; pci_read_config_byte(pci, PCI_REVISION_ID, &rev); return rev; } +#endif + +#if defined(COMPAT_PCM_TO_RATE_BIT) && defined(__SOUND_PCM_H) +/* New alsa core utility function */ +static inline unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate) +{ + static const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, + 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rates); i++) + if (rates[i] == rate) + return 1u << i; + return SNDRV_PCM_RATE_KNOT; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +# define task_pid_nr(current) ((current)->pid) + +# define sg_init_table(a,b) +# define sg_page(p) (sg->page) +# define sg_set_page(sglist,pg,sz,off) \ +do { \ + struct scatterlist *p=sglist; \ + p->page = pg; \ + p->length = sz; \ + p->offset = off; \ +} while (0) + +#define pr_err(fmt, arg...) \ + printk(KERN_ERR fmt, ##arg) +#endif + +#ifndef BIT_MASK +# define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +# define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +#define i2c_verify_client(dev) \ + ((dev->bus == &i2c_bus_type) ? to_i2c_client(dev) : NULL) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) +#define i2c_verify_client(dev) \ + ((dev->bus && 0 == strcmp(dev->bus->name, "i2c")) ? to_i2c_client(dev) : NULL) +#endif + +#ifndef USB_DEVICE_AND_INTERFACE_INFO +# define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ + | USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), .idProduct = (prod), \ + .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +#define get_unaligned_be16(a) \ + be16_to_cpu(get_unaligned((unsigned short *)(a))) +#define put_unaligned_be16(r, a) \ + put_unaligned(cpu_to_be16(r), ((unsigned short *)(a))) +#define get_unaligned_le16(a) \ + le16_to_cpu(get_unaligned((unsigned short *)(a))) +#define put_unaligned_le16(r, a) \ + put_unaligned(cpu_to_le16(r), ((unsigned short *)(a))) +#define get_unaligned_be32(a) \ + be32_to_cpu(get_unaligned((u32 *)(a))) +#define put_unaligned_be32(r, a) \ + put_unaligned(cpu_to_be32(r), ((u32 *)(a))) +#define get_unaligned_le32(a) \ + le32_to_cpu(get_unaligned((u32 *)(a))) +#define put_unaligned_le32(r, a) \ + put_unaligned(cpu_to_le32(r), ((u32 *)(a))) +#define get_unaligned_le64(a) \ + le64_to_cpu(get_unaligned((u64 *)(a))) +#define put_unaligned_le64(r, a) \ + put_unaligned(cpu_to_le64(r), ((u64 *)(a))) +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) +#ifdef CONFIG_PROC_FS +static inline struct proc_dir_entry *proc_create(const char *a, + mode_t b, struct proc_dir_entry *c, const struct file_operations *d) +{ + struct proc_dir_entry *e; + + e = create_proc_entry(a, b, c); + if (e) { + e->owner = THIS_MODULE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) + e->proc_fops = d; +#else + e->proc_fops = (struct file_operations *)d; +#endif + } + return e; +} +#endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +#ifdef CONFIG_PROC_FS +static inline struct proc_dir_entry *proc_create_data(const char *a, + mode_t b, struct proc_dir_entry *c, const struct file_operations *d, + void *f) +{ + struct proc_dir_entry *e; + + e = create_proc_entry(a, b, c); + if (e) { + e->owner = THIS_MODULE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) + e->proc_fops = d; +#else + e->proc_fops = (struct file_operations *)d; +#endif + e->data = f; + } + return e; +} +#endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) +#define hweight64(x) generic_hweight64(x) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +#define div64_u64(a,b) div64_64(a,b) + +#define clamp( x, l, h ) max_t( __typeof__( x ), \ + ( l ), \ + min_t( __typeof__( x ), \ + ( h ), \ + ( x ) ) ) + +#define dev_name(dev) ((dev)->bus_id) + +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +typedef unsigned long uintptr_t; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} +#endif + +#endif diff --git a/drivers/cmmb/siano/sms-cards.c b/drivers/cmmb/siano/sms-cards.c new file mode 100755 index 000000000000..9caeef416ec5 --- /dev/null +++ b/drivers/cmmb/siano/sms-cards.c @@ -0,0 +1,329 @@ +/* + * Card-specific functions for the Siano SMS1xxx USB dongle + * + * Copyright (c) 2008 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "sms-cards.h" + +struct usb_device_id smsusb_id_table[] = { + { USB_DEVICE(0x187f, 0x0010), + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0100), + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0200), + .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A }, + { USB_DEVICE(0x187f, 0x0201), + .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B }, + { USB_DEVICE(0x187f, 0x0300), + .driver_info = SMS1XXX_BOARD_SIANO_VEGA }, + { USB_DEVICE(0x2040, 0x1700), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT }, + { USB_DEVICE(0x2040, 0x1800), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A }, + { USB_DEVICE(0x2040, 0x1801), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, + { USB_DEVICE(0x2040, 0x2000), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2009), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 }, + { USB_DEVICE(0x2040, 0x200a), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2019), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x5500), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5510), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5520), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5530), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5580), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5590), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x187f, 0x0202), + .driver_info = SMS1XXX_BOARD_SIANO_NICE }, + { USB_DEVICE(0x187f, 0x0301), + .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, + { } /* Terminating entry */ + }; + +MODULE_DEVICE_TABLE(usb, smsusb_id_table); + +static struct sms_board sms_boards[] = { + [SMS_BOARD_UNKNOWN] = { + /* 0 */ + .name = "Unknown board", + }, + [SMS1XXX_BOARD_SIANO_STELLAR] = { + /* 1 */ + .name = + "Siano Stellar Digital Receiver", + .type = SMS_STELLAR, + .fw[DEVICE_MODE_DVBT_BDA] = + "sms1xxx-stellar-dvbt-01.fw", + }, + [SMS1XXX_BOARD_SIANO_NOVA_A] = { + /* 2 */ + .name = "Siano Nova A Digital Receiver", + .type = SMS_NOVA_A0, + .fw[DEVICE_MODE_DVBT_BDA] = + "sms1xxx-nova-a-dvbt-01.fw", + }, + [SMS1XXX_BOARD_SIANO_NOVA_B] = { + /* 3 */ + .name = "Siano Nova B Digital Receiver", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = + "sms1xxx-nova-b-dvbt-01.fw", + }, + [SMS1XXX_BOARD_SIANO_VEGA] = { + /* 4 */ + .name = "Siano Vega Digital Receiver", + .type = SMS_VEGA, + }, + [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { + /* 5 */ + .name = "Hauppauge Catamount", + .type = SMS_STELLAR, + .fw[DEVICE_MODE_DVBT_BDA] = + "sms1xxx-stellar-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { + /* 6 */ + .name = "Hauppauge Okemo-A", + .type = SMS_NOVA_A0, + .fw[DEVICE_MODE_DVBT_BDA] = + "sms1xxx-nova-a-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { + /* 7 */ + .name = "Hauppauge Okemo-B", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = + "sms1xxx-nova-b-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { + /* 8 */ + .name = "Hauppauge WinTV MiniStick", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .board_cfg.leds_power = 26, + .board_cfg.led0 = 27, + .board_cfg.led1 = 28, + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { + /* 9 */ + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .board_cfg.foreign_lna0_ctrl = 29, + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { + /* 10 */ + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .board_cfg.foreign_lna0_ctrl = 1, + }, + [SMS1XXX_BOARD_SIANO_NICE] = { + /* 11 */ + .name = "Siano Nice Digital Receiver", + .type = SMS_NOVA_B0, + }, + [SMS1XXX_BOARD_SIANO_VENICE] = { + /* 12 */ + .name = "Siano Venice Digital Receiver", + .type = SMS_VEGA, + }, +}; + +struct sms_board *sms_get_board(int id) +{ + BUG_ON(id >= ARRAY_SIZE(sms_boards)); + return &sms_boards[id]; +} + +static inline void sms_gpio_assign_11xx_default_led_config( + struct smscore_gpio_config *pGpioConfig) { + pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT; + pGpioConfig->InputCharacteristics = + SMS_GPIO_INPUTCHARACTERISTICS_NORMAL; + pGpioConfig->OutputDriving = SMS_GPIO_OUTPUTDRIVING_4mA; + pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUTSLEWRATE_0_45_V_NS; + pGpioConfig->PullUpDown = SMS_GPIO_PULLUPDOWN_NONE; +} + +int sms_board_event(struct smscore_device_t *coredev, + enum SMS_BOARD_EVENTS gevent) { + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + struct smscore_gpio_config MyGpioConfig; + + sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); + + switch (gevent) { + case BOARD_EVENT_POWER_INIT: /* including hotplug */ + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* set I/O and turn off all LEDs */ + smscore_gpio_configure(coredev, + board->board_cfg.leds_power, + &MyGpioConfig); + smscore_gpio_set_level(coredev, + board->board_cfg.leds_power, 0); + smscore_gpio_configure(coredev, board->board_cfg.led0, + &MyGpioConfig); + smscore_gpio_set_level(coredev, + board->board_cfg.led0, 0); + smscore_gpio_configure(coredev, board->board_cfg.led1, + &MyGpioConfig); + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* set I/O and turn off LNA */ + smscore_gpio_configure(coredev, + board->board_cfg.foreign_lna0_ctrl, + &MyGpioConfig); + smscore_gpio_set_level(coredev, + board->board_cfg.foreign_lna0_ctrl, + 0); + break; + } + break; /* BOARD_EVENT_BIND */ + + case BOARD_EVENT_POWER_SUSPEND: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.leds_power, 0); + smscore_gpio_set_level(coredev, + board->board_cfg.led0, 0); + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + smscore_gpio_set_level(coredev, + board->board_cfg.foreign_lna0_ctrl, + 0); + break; + } + break; /* BOARD_EVENT_POWER_SUSPEND */ + + case BOARD_EVENT_POWER_RESUME: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.leds_power, 1); + smscore_gpio_set_level(coredev, + board->board_cfg.led0, 1); + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + smscore_gpio_set_level(coredev, + board->board_cfg.foreign_lna0_ctrl, + 1); + break; + } + break; /* BOARD_EVENT_POWER_RESUME */ + + case BOARD_EVENT_BIND: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.leds_power, 1); + smscore_gpio_set_level(coredev, + board->board_cfg.led0, 1); + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + smscore_gpio_set_level(coredev, + board->board_cfg.foreign_lna0_ctrl, + 1); + break; + } + break; /* BOARD_EVENT_BIND */ + + case BOARD_EVENT_SCAN_PROG: + break; /* BOARD_EVENT_SCAN_PROG */ + case BOARD_EVENT_SCAN_COMP: + break; /* BOARD_EVENT_SCAN_COMP */ + case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL: + break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */ + case BOARD_EVENT_FE_LOCK: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 1); + break; + } + break; /* BOARD_EVENT_FE_LOCK */ + case BOARD_EVENT_FE_UNLOCK: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + } + break; /* BOARD_EVENT_FE_UNLOCK */ + case BOARD_EVENT_DEMOD_LOCK: + break; /* BOARD_EVENT_DEMOD_LOCK */ + case BOARD_EVENT_DEMOD_UNLOCK: + break; /* BOARD_EVENT_DEMOD_UNLOCK */ + case BOARD_EVENT_RECEPTION_MAX_4: + break; /* BOARD_EVENT_RECEPTION_MAX_4 */ + case BOARD_EVENT_RECEPTION_3: + break; /* BOARD_EVENT_RECEPTION_3 */ + case BOARD_EVENT_RECEPTION_2: + break; /* BOARD_EVENT_RECEPTION_2 */ + case BOARD_EVENT_RECEPTION_1: + break; /* BOARD_EVENT_RECEPTION_1 */ + case BOARD_EVENT_RECEPTION_LOST_0: + break; /* BOARD_EVENT_RECEPTION_LOST_0 */ + case BOARD_EVENT_MULTIPLEX_OK: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 1); + break; + } + break; /* BOARD_EVENT_MULTIPLEX_OK */ + case BOARD_EVENT_MULTIPLEX_ERRORS: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + } + break; /* BOARD_EVENT_MULTIPLEX_ERRORS */ + + default: + sms_err("Unknown SMS board event"); + break; + } + return 0; +} diff --git a/drivers/cmmb/siano/sms-cards.h b/drivers/cmmb/siano/sms-cards.h new file mode 100755 index 000000000000..be7bc8e9825e --- /dev/null +++ b/drivers/cmmb/siano/sms-cards.h @@ -0,0 +1,105 @@ +/* + * Card-specific functions for the Siano SMS1xxx USB dongle + * + * Copyright (c) 2008 Michael Krufky + * + * 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 +#include "smscoreapi.h" + +#define SMS_BOARD_UNKNOWN 0 +#define SMS1XXX_BOARD_SIANO_STELLAR 1 +#define SMS1XXX_BOARD_SIANO_NOVA_A 2 +#define SMS1XXX_BOARD_SIANO_NOVA_B 3 +#define SMS1XXX_BOARD_SIANO_VEGA 4 +#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5 +#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6 +#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7 +#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 +#define SMS1XXX_BOARD_SIANO_NICE 11 +#define SMS1XXX_BOARD_SIANO_VENICE 12 + +struct sms_board_gpio_cfg { + int foreign_lna0_ctrl; + int foreign_lna1_ctrl; + int foreign_lna2_ctrl; + int lna_vhf_exist; + int lna_vhf_ctrl; + int lna_uhf_exist; + int lna_uhf_ctrl; + int lna_uhf_d_ctrl; + int lna_sband_exist; + int lna_sband_ctrl; + int lna_sband_d_ctrl; + int leds_power; + int led0; + int led1; + int led2; + int led3; + int led4; + int ir; + int eeprom_wp; + int mrc_sense; + int mrc_pdn_resetn; + int mrc_gp0; /* mrcs spi int */ + int mrc_gp1; + int mrc_gp2; + int mrc_gp3; + int mrc_gp4; + int host_spi_gsp_ts_int; +}; + +struct sms_board { + enum sms_device_type_st type; + char *name, *fw[DEVICE_MODE_MAX]; + struct sms_board_gpio_cfg board_cfg; +}; + +struct sms_board *sms_get_board(int id); + +extern struct usb_device_id smsusb_id_table[]; +extern struct smscore_device_t *coredev; + +enum SMS_BOARD_EVENTS { + BOARD_EVENT_POWER_INIT, + BOARD_EVENT_POWER_SUSPEND, + BOARD_EVENT_POWER_RESUME, + BOARD_EVENT_BIND, + BOARD_EVENT_SCAN_PROG, + BOARD_EVENT_SCAN_COMP, + BOARD_EVENT_EMERGENCY_WARNING_SIGNAL, + BOARD_EVENT_FE_LOCK, + BOARD_EVENT_FE_UNLOCK, + BOARD_EVENT_DEMOD_LOCK, + BOARD_EVENT_DEMOD_UNLOCK, + BOARD_EVENT_RECEPTION_MAX_4, + BOARD_EVENT_RECEPTION_3, + BOARD_EVENT_RECEPTION_2, + BOARD_EVENT_RECEPTION_1, + BOARD_EVENT_RECEPTION_LOST_0, + BOARD_EVENT_MULTIPLEX_OK, + BOARD_EVENT_MULTIPLEX_ERRORS +}; + +int sms_board_event(struct smscore_device_t *coredev, + enum SMS_BOARD_EVENTS gevent); + +#endif /* __SMS_CARDS_H__ */ diff --git a/drivers/cmmb/siano/smschar.c b/drivers/cmmb/siano/smschar.c new file mode 100755 index 000000000000..d949f38ac733 --- /dev/null +++ b/drivers/cmmb/siano/smschar.c @@ -0,0 +1,808 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ +#include +#include +#include + +#include /* printk() */ +#include /* everything... */ +#include /* size_t */ +#include +#include +#include +#include /* cli(), *_flags */ +#include /* copy_*_user */ + +//#include +//#include +//#include +#include "smscoreapi.h" + +#include "smscharioctl.h" +#ifdef CONFIG_ANDROID_POWER +#include +#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"); +} diff --git a/drivers/cmmb/siano/smscharioctl.h b/drivers/cmmb/siano/smscharioctl.h new file mode 100755 index 000000000000..ccefaa83bb9c --- /dev/null +++ b/drivers/cmmb/siano/smscharioctl.h @@ -0,0 +1,55 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ +#ifndef __SMS_CHAR_IOCTL_H__ +#define __SMS_CHAR_IOCTL_H__ + +#include + +struct smschar_buffer_t { + unsigned long offset; /* offset in common buffer (mapped to user) */ + int size; +}; + +struct smschar_get_fw_filename_ioctl_t { + int mode; + char filename[200]; +}; + +struct smschar_send_fw_file_ioctl_t { + char *fw_buf; + int fw_size; +}; + +#define SMSCHAR_SET_DEVICE_MODE _IOW('K', 0, int) +#define SMSCHAR_GET_DEVICE_MODE _IOR('K', 1, int) +#define SMSCHAR_GET_BUFFER_SIZE _IOR('K', 2, int) +#define SMSCHAR_WAIT_GET_BUFFER _IOR('K', 3, struct smschar_buffer_t) +#define SMSCHAR_IS_DEVICE_PNP_EVENT _IOR('K', 4, int) +#define SMSCHAR_GET_FW_FILE_NAME \ + _IOWR('K', 5, struct smschar_get_fw_filename_ioctl_t) +#define SMSCHAR_SEND_FW_FILE \ + _IOW('K', 6, struct smschar_send_fw_file_ioctl_t) +#define SMSCHAR_CANCEL_WAIT_BUFFER _IO('K', 7) +#define SMSCHAR_RESET_DEVICE_DRVS _IO('K', 8) +#define SMSCHAR_STARTUP _IO('K', 9) +#define SMSCHAR_GET_RESUME_FLAG _IO('K', 10) +#define SMSCHAR_SET_RESUME_FLAG _IO('K', 11) +#endif /* __SMS_CHAR_IOCTL_H__ */ diff --git a/drivers/cmmb/siano/smscoreapi.c b/drivers/cmmb/siano/smscoreapi.c new file mode 100755 index 000000000000..150cbc34bb7d --- /dev/null +++ b/drivers/cmmb/siano/smscoreapi.c @@ -0,0 +1,2015 @@ +/**************************************************************** + + Siano Mobile Silicon, Inc. + MDTV receiver kernel modules. + Copyright (C) 2006-2008, Uri Shkolnik + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "smscoreapi.h" +#include "smsendian.h" +#include "sms-cards.h" +#include + +#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"); diff --git a/drivers/cmmb/siano/smscoreapi.h b/drivers/cmmb/siano/smscoreapi.h new file mode 100755 index 000000000000..ba9be1b81934 --- /dev/null +++ b/drivers/cmmb/siano/smscoreapi.h @@ -0,0 +1,547 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ + +#ifndef __SMS_CORE_API_H__ +#define __SMS_CORE_API_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "compat.h" + +#ifdef SMS_DVB3_SUBSYS +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#endif + +#define kmutex_init(_p_) mutex_init(_p_) +#define kmutex_lock(_p_) mutex_lock(_p_) +#define kmutex_trylock(_p_) mutex_trylock(_p_) +#define kmutex_unlock(_p_) mutex_unlock(_p_) + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define SMS_ALLOC_ALIGNMENT 128 +#define SMS_DMA_ALIGNMENT 16 +#define SMS_ALIGN_ADDRESS(addr) \ + ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) + +#define SMS_DEVICE_FAMILY2 1 +#define SMS_ROM_NO_RESPONSE 2 +#define SMS_DEVICE_NOT_READY 0x8000000 + +enum sms_device_type_st { + SMS_STELLAR = 0, + SMS_NOVA_A0, + SMS_NOVA_B0, + SMS_VEGA, + SMS_NUM_OF_DEVICE_TYPES +}; + +struct smscore_device_t; +struct smscore_client_t; +struct smscore_buffer_t; + +typedef int (*hotplug_t) (struct smscore_device_t *coredev, + struct device *device, int arrival); + +typedef int (*setmode_t) (void *context, int mode); +typedef void (*detectmode_t) (void *context, int *mode); +typedef int (*sendrequest_t) (void *context, void *buffer, size_t size); +typedef int (*loadfirmware_t) (void *context, void *buffer, size_t size); +typedef int (*preload_t) (void *context); +typedef int (*postload_t) (void *context); + +typedef int (*onresponse_t) (void *context, struct smscore_buffer_t *cb); +typedef void (*onremove_t) (void *context); + +struct smscore_buffer_t { + /* public members, once passed to clients can be changed freely */ + struct list_head entry; + int size; + int offset; + + /* private members, read-only for clients */ + void *p; + dma_addr_t phys; + unsigned long offset_in_common; +}; + +struct smsdevice_params_t { + struct device *device; + + int buffer_size; + int num_buffers; + + char devpath[32]; + unsigned long flags; + + setmode_t setmode_handler; + detectmode_t detectmode_handler; + sendrequest_t sendrequest_handler; + preload_t preload_handler; + postload_t postload_handler; + + void *context; + enum sms_device_type_st device_type; +}; + +struct smsclient_params_t { + int initial_id; + int data_type; + onresponse_t onresponse_handler; + onremove_t onremove_handler; + + void *context; +}; + +/* GPIO definitions for antenna frequency domain control (SMS8021) */ +#define SMS_ANTENNA_GPIO_0 1 +#define SMS_ANTENNA_GPIO_1 0 + +#define BW_8_MHZ 0 +#define BW_7_MHZ 1 +#define BW_6_MHZ 2 +#define BW_5_MHZ 3 +#define BW_ISDBT_1SEG 4 +#define BW_ISDBT_3SEG 5 + +#define MSG_HDR_FLAG_SPLIT_MSG 4 + +#define MAX_GPIO_PIN_NUMBER 31 + +#define HIF_TASK 11 +#define SMS_HOST_LIB 150 +#define DVBT_BDA_CONTROL_MSG_ID 201 + +#define SMS_MAX_PAYLOAD_SIZE 240 +#define SMS_TUNE_TIMEOUT 500 + +#define MSG_SMS_GPIO_CONFIG_REQ 507 +#define MSG_SMS_GPIO_CONFIG_RES 508 +#define MSG_SMS_GPIO_SET_LEVEL_REQ 509 +#define MSG_SMS_GPIO_SET_LEVEL_RES 510 +#define MSG_SMS_GPIO_GET_LEVEL_REQ 511 +#define MSG_SMS_GPIO_GET_LEVEL_RES 512 +#define MSG_SMS_RF_TUNE_REQ 561 +#define MSG_SMS_RF_TUNE_RES 562 +#define MSG_SMS_INIT_DEVICE_REQ 578 +#define MSG_SMS_INIT_DEVICE_RES 579 +#define MSG_SMS_ADD_PID_FILTER_REQ 601 +#define MSG_SMS_ADD_PID_FILTER_RES 602 +#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 +#define MSG_SMS_REMOVE_PID_FILTER_RES 604 +#define MSG_SMS_DAB_CHANNEL 607 +#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 +#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 +#define MSG_SMS_GET_STATISTICS_REQ 615 +#define MSG_SMS_GET_STATISTICS_RES 616 +#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 +#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 +#define MSG_SMS_GET_STATISTICS_EX_REQ 653 +#define MSG_SMS_GET_STATISTICS_EX_RES 654 +#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 + +#define MSG_SMS_SET_PERIODIC_STATS_REQ 658 +#define MSG_SMS_SET_PERIODIC_STATS_RES 659 + +#define MSG_SMS_DATA_DOWNLOAD_REQ 660 +#define MSG_SMS_DATA_DOWNLOAD_RES 661 +#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 +#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 +#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 +#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 +#define MSG_SMS_GET_VERSION_EX_REQ 668 +#define MSG_SMS_GET_VERSION_EX_RES 669 +#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 +#define MSG_SMS_I2C_SET_FREQ_REQ 685 +#define MSG_SMS_GENERIC_I2C_REQ 687 +#define MSG_SMS_GENERIC_I2C_RES 688 +#define MSG_SMS_DVBT_BDA_DATA 693 +#define MSG_SW_RELOAD_REQ 697 +#define MSG_SMS_DATA_MSG 699 +#define MSG_SW_RELOAD_START_REQ 702 +#define MSG_SW_RELOAD_START_RES 703 +#define MSG_SW_RELOAD_EXEC_REQ 704 +#define MSG_SW_RELOAD_EXEC_RES 705 +#define MSG_SMS_SPI_INT_LINE_SET_REQ 710 +#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 +#define MSG_SMS_GPIO_CONFIG_EX_RES 713 +#define MSG_SMS_ISDBT_TUNE_REQ 776 +#define MSG_SMS_ISDBT_TUNE_RES 777 + +#define MSG_SMS_LOOPBACK_REQ 718 +#define MSG_SMS_LOOPBACK_RES 719 + + +#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ + (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ + (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ +} while (0) +#define SMS_INIT_MSG(ptr, type, len) \ + SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len) + +enum SMS_DVB3_EVENTS { + DVB3_EVENT_INIT = 0, + DVB3_EVENT_SLEEP, + DVB3_EVENT_HOTPLUG, + DVB3_EVENT_FE_LOCK, + DVB3_EVENT_FE_UNLOCK, + DVB3_EVENT_UNC_OK, + DVB3_EVENT_UNC_ERR +}; + +enum SMS_DEVICE_MODE { + DEVICE_MODE_NONE = -1, + DEVICE_MODE_DVBT = 0, + DEVICE_MODE_DVBH, + DEVICE_MODE_DAB_TDMB, + DEVICE_MODE_DAB_TDMB_DABIP, + DEVICE_MODE_DVBT_BDA, + DEVICE_MODE_ISDBT, + DEVICE_MODE_ISDBT_BDA, + DEVICE_MODE_CMMB, + DEVICE_MODE_RAW_TUNER, + DEVICE_MODE_MAX, +}; + +struct SmsMsgHdr_ST { + u16 msgType; + u8 msgSrcId; + u8 msgDstId; + u16 msgLength; /* Length of entire message, including header */ + u16 msgFlags; +}; + +struct SmsMsgData_ST { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[1]; +}; + +struct SmsDataDownload_ST { + struct SmsMsgHdr_ST xMsgHeader; + u32 MemAddr; + u8 Payload[SMS_MAX_PAYLOAD_SIZE]; +}; + +struct SmsVersionRes_ST { + struct SmsMsgHdr_ST xMsgHeader; + + u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ + u8 Step; /* 0 - Step A */ + u8 MetalFix; /* 0 - Metal 0 */ + + u8 FirmwareId; /* 0xFF ROM, otherwise the + * value indicated by + * SMSHOSTLIB_DEVICE_MODES_E */ + u8 SupportedProtocols; /* Bitwise OR combination of + * supported protocols */ + + u8 VersionMajor; + u8 VersionMinor; + u8 VersionPatch; + u8 VersionFieldPatch; + + u8 RomVersionMajor; + u8 RomVersionMinor; + u8 RomVersionPatch; + u8 RomVersionFieldPatch; + + u8 TextLabel[34]; +}; + +struct SmsFirmware_ST { + u32 CheckSum; + u32 Length; + u32 StartAddress; + u8 Payload[1]; +}; + +struct SMSHOSTLIB_STATISTICS_ST { + u32 Reserved; /* Reserved */ + + /* Common parameters */ + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + /* Reception quality */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ + u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF + * indicate N/A, valid only for DVB-T/H */ + u32 MFER; /* DVB-H frame error rate in percentage, + * 0xFFFFFFFF indicate N/A, valid + * only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + + /* Transmission parameters, valid only for DVB-T/H */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, + * for DVB-T/H FFT mode carriers in Kilos */ + u32 ModemState; /* from SMS_DvbModemState_ET */ + u32 GuardInterval; /* Guard Interval, 1 divided by value */ + u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */ + u32 LPCodeRate; /* Low Priority Code Rate from + * SMS_DvbModemState_ET */ + u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */ + u32 Constellation; /* Constellation from SMS_Constellation_ET */ + + /* Burst parameters, valid only for DVB-H */ + u32 BurstSize; /* Current burst size in bytes */ + u32 BurstDuration; /* Current burst duration in mSec */ + u32 BurstCycleTime; /* Current burst cycle time in mSec */ + u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec, + * as calculated by demodulator */ + u32 NumOfRows; /* Number of rows in MPE table */ + u32 NumOfPaddCols; /* Number of padding columns in MPE table */ + u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */ + /* Burst parameters */ + u32 ErrorTSPackets; /* Number of erroneous transport-stream + * packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include + * errors after MPE RS decoding */ + u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors + * after MPE RS decoding */ + u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected + * by MPE RS decoding */ + + /* Common params */ + u32 BERErrorCount; /* Number of errornous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + + /* Interface information */ + u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + + /* DAB/T-DMB */ + u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + + /* DVB-H TPS parameters */ + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + * if set to 0xFFFFFFFF cell_id not + * yet recovered */ + +}; + +struct SmsMsgStatisticsInfo_ST { + u32 RequestResult; + + struct SMSHOSTLIB_STATISTICS_ST Stat; + + /* Split the calc of the SNR in DAB */ + u32 Signal; /* dB */ + u32 Noise; /* dB */ + +}; + +struct smscore_gpio_config { +#define SMS_GPIO_DIRECTION_INPUT 0 +#define SMS_GPIO_DIRECTION_OUTPUT 1 + u8 Direction; + +#define SMS_GPIO_PULLUPDOWN_NONE 0 +#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 +#define SMS_GPIO_PULLUPDOWN_PULLUP 2 +#define SMS_GPIO_PULLUPDOWN_KEEPER 3 + u8 PullUpDown; + +#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 +#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 + u8 InputCharacteristics; + +#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 0 /* 10xx */ +#define SMS_GPIO_OUTPUTSLEWRATE_FAST 1 /* 10xx */ + +#define SMS_GPIO_OUTPUTSLEWRATE_0_45_V_NS 0 /* 11xx */ +#define SMS_GPIO_OUTPUTSLEWRATE_0_9_V_NS 1 /* 11xx */ +#define SMS_GPIO_OUTPUTSLEWRATE_1_7_V_NS 2 /* 11xx */ +#define SMS_GPIO_OUTPUTSLEWRATE_3_3_V_NS 3 /* 11xx */ + u8 OutputSlewRate; + +#define SMS_GPIO_OUTPUTDRIVING_S_4mA 0 /* 10xx */ +#define SMS_GPIO_OUTPUTDRIVING_S_8mA 1 /* 10xx */ +#define SMS_GPIO_OUTPUTDRIVING_S_12mA 2 /* 10xx */ +#define SMS_GPIO_OUTPUTDRIVING_S_16mA 3 /* 10xx */ + +#define SMS_GPIO_OUTPUTDRIVING_1_5mA 0 /* 11xx */ +#define SMS_GPIO_OUTPUTDRIVING_2_8mA 1 /* 11xx */ +#define SMS_GPIO_OUTPUTDRIVING_4mA 2 /* 11xx */ +#define SMS_GPIO_OUTPUTDRIVING_7mA 3 /* 11xx */ +#define SMS_GPIO_OUTPUTDRIVING_10mA 4 /* 11xx */ +#define SMS_GPIO_OUTPUTDRIVING_11mA 5 /* 11xx */ +#define SMS_GPIO_OUTPUTDRIVING_14mA 6 /* 11xx */ +#define SMS_GPIO_OUTPUTDRIVING_16mA 7 /* 11xx */ + u8 OutputDriving; +}; + +#ifdef SMS_DVB3_SUBSYS + +struct smsdvb_client_t { + struct list_head entry; + + struct smscore_device_t *coredev; + struct smscore_client_t *smsclient; + + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dvb_frontend frontend; + + fe_status_t fe_status; + int fe_ber, fe_snr, fe_unc, fe_signal_strength; + + struct completion tune_done, stat_done; + + /* todo: save freq/band instead whole struct */ + struct dvb_frontend_parameters fe_params; + +}; +#endif /* SMS_DVB3_SUBSYS */ + +extern void smsspi_poweron(void); +extern void smsspi_off(void); +extern void smscore_registry_setmode(char *devpath, int mode); +extern int smscore_registry_getmode(char *devpath); + +extern int smscore_register_hotplug(hotplug_t hotplug); +extern void smscore_unregister_hotplug(hotplug_t hotplug); + +extern int smscore_register_device(struct smsdevice_params_t *params, + struct smscore_device_t **coredev); +extern void smscore_unregister_device(struct smscore_device_t *coredev); + +extern int smscore_start_device(struct smscore_device_t *coredev); +extern int smscore_load_firmware(struct smscore_device_t *coredev, + char *filename, + loadfirmware_t loadfirmware_handler); +extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode); +extern int smscore_get_device_mode(struct smscore_device_t *coredev); +// Peter add on June 18, 2009 +extern int smscore_reset_device_drvs(struct smscore_device_t *coredev); +extern int smscore_get_fw_filename(struct smscore_device_t *coredev, int mode, + char *filename); +extern int smscore_send_fw_file(struct smscore_device_t *coredev, u8 *ufwbuf, + int size); + +extern int smscore_register_client(struct smscore_device_t *coredev, + struct smsclient_params_t *params, + struct smscore_client_t **client); +extern void smscore_unregister_client(struct smscore_client_t *client); + +extern int smsclient_sendrequest(struct smscore_client_t *client, + void *buffer, size_t size); +extern void smscore_onresponse(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb); + +extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); +extern int smscore_map_common_buffer(struct smscore_device_t *coredev, + struct vm_area_struct *vma); + +extern struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t + *coredev); +extern void smscore_putbuffer(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb); + +int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, + struct smscore_gpio_config *pGpioConfig); +int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, + u8 NewLevel); +int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, + u8 *level); + +void smscore_set_board_id(struct smscore_device_t *core, int id); +int smscore_get_board_id(struct smscore_device_t *core); + +#ifdef SMS_HOSTLIB_SUBSYS +extern int smschar_register(void); +extern void smschar_unregister(void); +#endif + +#ifdef SMS_NET_SUBSYS +extern int smsnet_register(void); +extern void smsnet_unregister(void); +#endif + +#ifdef SMS_DVB3_SUBSYS +extern int smsdvb_register(void); +extern void smsdvb_unregister(void); +#endif + +#ifdef SMS_USB_DRV +extern int smsusb_register(void); +extern void smsusb_unregister(void); +#endif + +#ifdef SMS_SDIO_DRV +extern int smssdio_register(void); +extern void smssdio_unregister(void); +#endif + +#ifdef SMS_SPI_ROCKCHIP +extern int smsspi_register(void); +extern void smsspi_unregister(void); +#endif + +/* ------------------------------------------------------------------------ */ + +extern int sms_debug; + +#define DBG_INFO 1 +#define DBG_ADV 2 + + +#define sms_printk(kern, fmt, arg...) \ + printk(kern " " fmt "\n", ##arg) // to save log + +#define dprintk(kern, lvl, fmt, arg...) do {\ + if (sms_debug & lvl) \ + sms_printk(kern, fmt, ##arg); } while (0) + +#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) +#define sms_err(fmt, arg...) \ + sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) +#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) +#define sms_info(fmt, arg...) \ + dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) +#define sms_debug(fmt, arg...) \ + dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)// + + +//define the gpio used +#define CMMB_1186_SPIIRQ RK2818_PIN_PA6 //This Pin is SDK Board GPIOPortA_Pin6 +#define CMMB_1186_POWER_DOWN FPGA_PIO2_09 +#define CMMB_1186_POWER_ENABLE FPGA_PIO4_03 +#define CMMB_1186_POWER_RESET FPGA_PIO2_06 +#endif /* __SMS_CORE_API_H__ */ diff --git a/drivers/cmmb/siano/smsdbg_prn.h b/drivers/cmmb/siano/smsdbg_prn.h new file mode 100755 index 000000000000..71de343b5c62 --- /dev/null +++ b/drivers/cmmb/siano/smsdbg_prn.h @@ -0,0 +1,63 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ + +#ifndef _SMS_DBG_H_ +#define _SMS_DBG_H_ + +#include +#include + +/************************************************************************/ +/* Debug Zones definitions. */ +/************************************************************************/ +#undef PERROR +# define PERROR(fmt, args...) \ + printk(KERN_ERR "spibus error: line %d- %s(): " fmt, __LINE__,\ + __func__, ## args) +#undef PWARNING +# define PWARNING(fmt, args...) \ + printk(KERN_WARNING "spibus warning: line %d- %s(): " fmt, __LINE__, \ + __func__, ## args) + +/* the debug macro - conditional compilation from the makefile */ +// to enable log + + +//ROCK Enbale Interruption +//#define SPIBUS_DEBUG 1 + +#undef PDEBUG /* undef it, just in case */ +#ifdef SPIBUS_DEBUG + +#define PDEBUG(fmt, args...) \ + printk(KERN_DEBUG " " fmt,## args) + +#else +# define PDEBUG(fmt, args...) /* not debugging: nothing */ +#endif + +/* The following defines are used for printing and +are mandatory for compilation. */ +#define TXT(str) str +#define PRN_DBG(str) PDEBUG str +#define PRN_ERR(str) PERROR str + +#endif /*_SMS_DBG_H_*/ diff --git a/drivers/cmmb/siano/smsendian.c b/drivers/cmmb/siano/smsendian.c new file mode 100755 index 000000000000..d79aa051269a --- /dev/null +++ b/drivers/cmmb/siano/smsendian.c @@ -0,0 +1,100 @@ +/**************************************************************** + + Siano Mobile Silicon, Inc. + MDTV receiver kernel modules. + Copyright (C) 2006-2009, Uri Shkolnik + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ****************************************************************/ + +#include + +#include "smsendian.h" +#include "smscoreapi.h" + +void smsendian_handle_tx_message(void *buffer) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + int i; + int msgWords; + + switch (msg->xMsgHeader.msgType) { + case MSG_SMS_DATA_DOWNLOAD_REQ: + { + msg->msgData[0] = le32_to_cpu(msg->msgData[0]); + break; + } + + default: + msgWords = (msg->xMsgHeader.msgLength - + sizeof(struct SmsMsgHdr_ST))/4; + + for (i = 0; i < msgWords; i++) + msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + + break; + } +#endif /* __BIG_ENDIAN */ +} + +void smsendian_handle_rx_message(void *buffer) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + int i; + int msgWords; + + switch (msg->xMsgHeader.msgType) { + case MSG_SMS_GET_VERSION_EX_RES: + { + struct SmsVersionRes_ST *ver = + (struct SmsVersionRes_ST *) msg; + ver->ChipModel = le16_to_cpu(ver->ChipModel); + break; + } + + case MSG_SMS_DVBT_BDA_DATA: + case MSG_SMS_DAB_CHANNEL: + case MSG_SMS_DATA_MSG: + { + break; + } + + default: + { + msgWords = (msg->xMsgHeader.msgLength - + sizeof(struct SmsMsgHdr_ST))/4; + + for (i = 0; i < msgWords; i++) + msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + + break; + } + } +#endif /* __BIG_ENDIAN */ +} + +void smsendian_handle_message_header(void *msg) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg; + + phdr->msgType = le16_to_cpu(phdr->msgType); + phdr->msgLength = le16_to_cpu(phdr->msgLength); + phdr->msgFlags = le16_to_cpu(phdr->msgFlags); +#endif /* __BIG_ENDIAN */ +} + diff --git a/drivers/cmmb/siano/smsendian.h b/drivers/cmmb/siano/smsendian.h new file mode 100755 index 000000000000..7fbedc6a6527 --- /dev/null +++ b/drivers/cmmb/siano/smsendian.h @@ -0,0 +1,32 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2009, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ + +#ifndef __SMS_ENDIAN_H__ +#define __SMS_ENDIAN_H__ + +#include + +void smsendian_handle_tx_message(void *buffer); +void smsendian_handle_rx_message(void *buffer); +void smsendian_handle_message_header(void *msg); + +#endif /* __SMS_ENDIAN_H__ */ + diff --git a/drivers/cmmb/siano/smsspicommon.c b/drivers/cmmb/siano/smsspicommon.c new file mode 100755 index 000000000000..2108398fe6c4 --- /dev/null +++ b/drivers/cmmb/siano/smsspicommon.c @@ -0,0 +1,439 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ +#include "smsspicommon.h" +#include "smsdbg_prn.h" +#include "smscoreapi.h" + + + +static struct _rx_buffer_st *smsspi_handle_unused_bytes_buf( + struct _spi_dev *dev, + struct _rx_buffer_st *buf, int offset, int len, + int unused_bytes) +{ + struct _rx_buffer_st *tmp_buf; + + + tmp_buf = dev->cb.allocate_rx_buf(dev->context, + RX_PACKET_SIZE); + + + if (!tmp_buf) { + sms_err("Failed to allocate RX buffer.\n"); + return NULL; + } + if (unused_bytes > 0) { + /* Copy the remaining bytes to the end of + alignment block (256 bytes) so next read + will be aligned. */ + int align_block = + (((unused_bytes + SPI_PACKET_SIZE - + 1) >> SPI_PACKET_SIZE_BITS) << + SPI_PACKET_SIZE_BITS); + memset(tmp_buf->ptr, 0, + align_block - unused_bytes); + memcpy((char *)tmp_buf->ptr + + (align_block - unused_bytes), + (char *)buf->ptr + offset + len - + unused_bytes, unused_bytes); + } + //sms_info("smsspi_handle_unused_bytes_buf unused_bytes=0x%x offset=0x%x len=0x%x \n",unused_bytes,offset,len); + return tmp_buf; +} + +static struct _rx_buffer_st *smsspi_common_find_msg(struct _spi_dev *dev, + struct _rx_buffer_st *buf, int offset, int len, + int *unused_bytes, int *missing_bytes) +{ + int i; + int recieved_bytes, padded_msg_len; + int align_fix; + int msg_offset; + unsigned char *ptr = (unsigned char *)buf->ptr + offset; + if (unused_bytes == NULL || missing_bytes == NULL) + return NULL; + + *missing_bytes = 0; + *unused_bytes = 0; + + //sms_info("entering with %d bytes.\n", len); + for (i = 0; i < len; i++, ptr++) { + switch (dev->rxState) { + case RxsWait_a5: + dev->rxState = + ((*ptr & 0xff) == 0xa5) ? RxsWait_5a : RxsWait_a5; + dev->rxPacket.msg_offset = + (unsigned long)ptr - (unsigned long)buf->ptr + 4; + break; + case RxsWait_5a: + if ((*ptr & 0xff) == 0x5a) { + dev->rxState = RxsWait_e7; + } + else { + dev->rxState = RxsWait_a5; + i--; + ptr--; // re-scan current byte + } + //sms_info("state %d.\n", dev->rxState); + break; + case RxsWait_e7: + if ((*ptr & 0xff) == 0xe7) { + dev->rxState = RxsWait_7e; + } + else { + dev->rxState = RxsWait_a5; + i--; + ptr--; // re-scan current byte + } + //sms_info("state %d.\n", dev->rxState); + break; + case RxsWait_7e: + if ((*ptr & 0xff) == 0x7e) { + dev->rxState = RxsTypeH; + } + else { + dev->rxState = RxsWait_a5; + i--; + ptr--; // re-scan current byte + } + //sms_info("state %d.\n", dev->rxState); + break; + case RxsTypeH: + dev->rxPacket.msg_buf = buf; + dev->rxPacket.msg_offset = + (unsigned long)ptr - (unsigned long)buf->ptr; + dev->rxState = RxsTypeL; + //sms_info("state %d.\n", dev->rxState); + break; + case RxsTypeL: + dev->rxState = RxsGetSrcId; + //sms_info("state %d.\n", dev->rxState); + break; + case RxsGetSrcId: + dev->rxState = RxsGetDstId; + //sms_info("state %d.\n", dev->rxState); + break; + case RxsGetDstId: + dev->rxState = RxsGetLenL; + //sms_info("state %d.\n", dev->rxState); + break; + case RxsGetLenL: + dev->rxState = RxsGetLenH; + dev->rxPacket.msg_len = (*ptr & 0xff); + //sms_info("state %d.\n", dev->rxState); + break; + case RxsGetLenH: + dev->rxState = RxsFlagsL; + dev->rxPacket.msg_len += (*ptr & 0xff) << 8; + //sms_info("state %d.\n", dev->rxState); + break; + case RxsFlagsL: + dev->rxState = RxsFlagsH; + dev->rxPacket.msg_flags = (*ptr & 0xff); + //sms_info("state %d.\n", dev->rxState); + break; + case RxsFlagsH: + dev->rxState = RxsData; + dev->rxPacket.msg_flags += (*ptr & 0xff) << 8; + //sms_info("state %d.\n", dev->rxState); + break; + case RxsData: + recieved_bytes = + len + offset - dev->rxPacket.msg_offset; + padded_msg_len = + ((dev->rxPacket.msg_len + 4 + SPI_PACKET_SIZE - + 1) >> SPI_PACKET_SIZE_BITS) << + SPI_PACKET_SIZE_BITS; + if (recieved_bytes < padded_msg_len) { + *unused_bytes = 0; + *missing_bytes = padded_msg_len - + recieved_bytes; + + + return buf; + } + dev->rxState = RxsWait_a5; + if (dev->cb.msg_found_cb) { + align_fix = 0; + if (dev->rxPacket. + msg_flags & MSG_HDR_FLAG_SPLIT_MSG_HDR) { + align_fix = + (dev->rxPacket. + msg_flags >> 8) & 0x3; + /* The FW aligned the message data + therefore - alignment bytes should be + thrown away. Throw the alignment bytes + by moving the header ahead over the + alignment bytes. */ + if (align_fix) { + int length; + ptr = + (unsigned char *)dev->rxPacket. + msg_buf->ptr + + dev->rxPacket.msg_offset; + + /* Restore header to original + state before alignment changes + */ + length = + (ptr[5] << 8) | ptr[4]; + length -= align_fix; + ptr[5] = length >> 8; + ptr[4] = length & 0xff; + /* Zero alignment flags */ + ptr[7] &= 0xfc; + + for (i = MSG_HDR_LEN - 1; + i >= 0; i--) { + ptr[i + align_fix] = + ptr[i]; + } + dev->rxPacket.msg_offset += + align_fix; + } + } + + sms_info("Msg found and sent to callback func.\n"); + + /* force all messages to start on + * 4-byte boundary */ + msg_offset = dev->rxPacket.msg_offset; + if (msg_offset & 0x3) { + msg_offset &= (~0x3); + memmove((unsigned char *) + (dev->rxPacket.msg_buf->ptr) + + msg_offset, + (unsigned char *) + (dev->rxPacket.msg_buf->ptr) + + dev->rxPacket.msg_offset, + dev->rxPacket.msg_len - + align_fix); + } + + *unused_bytes = + len + offset - dev->rxPacket.msg_offset - + dev->rxPacket.msg_len; + + /* In any case we got here - unused_bytes + * should not be 0 Because we want to force + * reading at least 256 after the end + of any found message */ + if (*unused_bytes == 0) + *unused_bytes = -1; + + buf = smsspi_handle_unused_bytes_buf(dev, buf, + offset, len, *unused_bytes); + + + + dev->cb.msg_found_cb(dev->context, + dev->rxPacket.msg_buf, + msg_offset, + dev->rxPacket.msg_len - + align_fix); + + + *missing_bytes = 0; + return buf; + } else { + sms_info("Msg found but no callback. therefore - thrown away.\n"); + } + sms_info("state %d.\n", dev->rxState); + break; + } + } + + if (dev->rxState == RxsWait_a5) { + *unused_bytes = 0; + *missing_bytes = 0; + + return buf; + } else { + /* Workaround to corner case: if the last byte of the buffer + is "a5" (first byte of the preamble), the host thinks it should + send another 256 bytes. In case the a5 is the firmware + underflow byte, this will cause an infinite loop, so we check + for this case explicity. */ + if (dev->rxState == RxsWait_5a) { + if ((*(ptr - 2) == 0xa5) || (*((unsigned int*)(ptr-4)) == *((unsigned int*)(ptr-8)))) { + dev->rxState = RxsWait_a5; + *unused_bytes = 0; + *missing_bytes = 0; + + return buf; + } + } + + if ((dev->rxState == RxsWait_5a) && (*(ptr - 2) == 0xa5)) { + dev->rxState = RxsWait_a5; + *unused_bytes = 0; + *missing_bytes = 0; + + return buf; + } + + if (dev->rxPacket.msg_offset >= (SPI_PACKET_SIZE + 4)) + /* adding 4 for the preamble. */ + { /*The packet will be copied to a new buffer + and rescaned by the state machine */ + struct _rx_buffer_st *tmp_buf = buf; + *unused_bytes = dev->rxState - RxsWait_a5; + tmp_buf = smsspi_handle_unused_bytes_buf(dev, buf, + offset, len, *unused_bytes); + dev->rxState = RxsWait_a5; + + dev->cb.free_rx_buf(dev->context, buf); + + + *missing_bytes = 0; + return tmp_buf; + } else { + /* report missing bytes and continue + with message scan. */ + *unused_bytes = 0; + *missing_bytes = SPI_PACKET_SIZE; + return buf; + } + } +} + +void smsspi_common_transfer_msg(struct _spi_dev *dev, struct _spi_msg *txmsg, + int padding_allowed) +{ + int len, bytes_to_transfer; + unsigned long tx_phy_addr; + int missing_bytes, tx_bytes; + int offset, unused_bytes; + int align_block; + char *txbuf; + struct _rx_buffer_st *buf, *tmp_buf; + + len = 0; + if (!dev->cb.transfer_data_cb) { + sms_err("function called while module is not initialized.\n"); + return; + } + if (txmsg == 0) { + bytes_to_transfer = SPI_PACKET_SIZE; + txbuf = 0; + tx_phy_addr = 0; + tx_bytes = 0; + } else { + tx_bytes = txmsg->len; + if (padding_allowed) + bytes_to_transfer = + (((tx_bytes + SPI_PACKET_SIZE - + 1) >> SPI_PACKET_SIZE_BITS) << + SPI_PACKET_SIZE_BITS); + else + bytes_to_transfer = (((tx_bytes + 3) >> 2) << 2); + txbuf = txmsg->buf; + tx_phy_addr = txmsg->buf_phy_addr; + } + offset = 0; + unused_bytes = 0; + + buf = + dev->cb.allocate_rx_buf(dev->context, + RX_PACKET_SIZE + SPI_PACKET_SIZE); + + + if (!buf) { + sms_err("Failed to allocate RX buffer.\n"); + return; + } + while (bytes_to_transfer || unused_bytes) { + if ((unused_bytes <= 0) && (bytes_to_transfer > 0)) { + len = min(bytes_to_transfer, RX_PACKET_SIZE); + //sms_info("transfering block of %d bytes\n", len); + dev->cb.transfer_data_cb(dev->phy_context, + (unsigned char *)txbuf, + tx_phy_addr, + (unsigned char *)buf->ptr + offset, + buf->phy_addr + offset, len); + } + + tmp_buf = + smsspi_common_find_msg(dev, buf, offset, len, + &unused_bytes, &missing_bytes); + + + //sms_info("smsspi_common_transfer_msg unused_bytes=0x%x missing_bytes=0x%x\n", unused_bytes, missing_bytes); + + if (bytes_to_transfer) + bytes_to_transfer -= len; + + if (tx_bytes) + tx_bytes -= len; + + if (missing_bytes) + offset += len; + + if (unused_bytes) { + /* In this case tmp_buf is a new buffer allocated + * in smsspi_common_find_msg + * and it already contains the unused bytes */ + if (unused_bytes > 0) { + align_block = + (((unused_bytes + SPI_PACKET_SIZE - + 1) >> SPI_PACKET_SIZE_BITS) << + SPI_PACKET_SIZE_BITS); + len = align_block; + } + offset = 0; + buf = tmp_buf; + + } + if (tx_bytes <= 0) { + txbuf = 0; + tx_bytes = 0; + } + if (bytes_to_transfer < missing_bytes) { + bytes_to_transfer = + (((missing_bytes + SPI_PACKET_SIZE - + 1) >> SPI_PACKET_SIZE_BITS) << + SPI_PACKET_SIZE_BITS); + sms_info("a message was found, adding bytes to transfer, txmsg %d, total %d\n" + , tx_bytes, bytes_to_transfer); + } + } + + + dev->cb.free_rx_buf(dev->context, buf); +} + +int smsspicommon_init(struct _spi_dev *dev, void *context, void *phy_context, + struct _spi_dev_cb_st *cb) +{ + sms_info("entering.\n"); + if (cb->transfer_data_cb == 0 || + cb->msg_found_cb == 0 || + cb->allocate_rx_buf == 0 || cb->free_rx_buf == 0) { + sms_err("Invalid input parameters of init routine.\n"); + return -1; + } + dev->context = context; + dev->phy_context = phy_context; + memcpy(&dev->cb, cb, sizeof(struct _spi_dev_cb_st)); + dev->rxState = RxsWait_a5; + sms_info("exiting.\n"); + return 0; +} diff --git a/drivers/cmmb/siano/smsspicommon.h b/drivers/cmmb/siano/smsspicommon.h new file mode 100755 index 000000000000..cfcc6b1e0452 --- /dev/null +++ b/drivers/cmmb/siano/smsspicommon.h @@ -0,0 +1,96 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ +#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<. + +****************************************************************/ +/*! + \file spibusdrv.c + + \brief spi bus driver module + + This file contains implementation of the spi bus driver. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smscoreapi.h" +#include "smsdbg_prn.h" +#include "smsspicommon.h" +#include "smsspiphy.h" +#include + +#define ANDROID_2_6_25 +#ifdef ANDROID_2_6_25 +#include +#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"); +} diff --git a/drivers/cmmb/siano/smsspiphy.h b/drivers/cmmb/siano/smsspiphy.h new file mode 100755 index 000000000000..55d76b96db9a --- /dev/null +++ b/drivers/cmmb/siano/smsspiphy.h @@ -0,0 +1,38 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ + +#ifndef __SMS_SPI_PHY_H__ +#define __SMS_SPI_PHY_H__ + +void smsspibus_xfer(void *context, unsigned char *txbuf, + unsigned long txbuf_phy_addr, unsigned char *rxbuf, + unsigned long rxbuf_phy_addr, int len); +void *smsspiphy_init(void *context, void (*smsspi_interruptHandler) (void *), + void *intr_context); +void smsspiphy_deinit(void *context); +void smschipreset(void *context); +void WriteFWtoStellar(void *pSpiPhy, unsigned char *pFW, unsigned long Len); +void prepareForFWDnl(void *pSpiPhy); +void fwDnlComplete(void *context, int App); +void smsspibus_ssp_suspend(void* context ); +int smsspibus_ssp_resume(void* context); + +#endif /* __SMS_SPI_PHY_H__ */ diff --git a/drivers/cmmb/siano/smsspiphy_pxa.c b/drivers/cmmb/siano/smsspiphy_pxa.c new file mode 100755 index 000000000000..5215093223b6 --- /dev/null +++ b/drivers/cmmb/siano/smsspiphy_pxa.c @@ -0,0 +1,732 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ +//#define PXA_310_LV + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "smsdbg_prn.h" +#include +#include +#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 + +static unsigned int dma_rxbuf_phy_addr ; +static unsigned int dma_txbuf_phy_addr ; + +static int rx_dma_channel =0 ; +static int tx_dma_channel =0 ; +static volatile int dma_len = 0 ; +static volatile int tx_len = 0 ; + +static struct ssp_dev* panic_sspdev = NULL ; + + +extern void smscore_panic_print(void); +extern void spilog_panic_print(void) ; +static void chip_powerdown(); +extern void smschar_reset_device(void); + +static int sms_panic_handler(struct notifier_block *this, + unsigned long event, + void *unused) +{ + static int panic_event_handled = 0; + if(!panic_event_handled) + { + smscore_panic_print() ; + spilog_panic_print() ; + printk("last tx_len = %d\n",tx_len) ; + printk("last DMA len = %d\n",dma_len) ; +#if 0 + printk("rxbuf_addr=[0x%x],Rx DSADR=[0x%x] DTADR=[0x%x] DCSR=[0x%x] DCMD=[0x%x]\n", + dma_rxbuf_phy_addr, DSADR(rx_dma_channel),DTADR(rx_dma_channel), + DCSR(rx_dma_channel),DCMD(rx_dma_channel) ); + + printk("txbuf_addr=[0x%x],Tx DSADR=[0x%x] DTADR=[0x%x] DCSR[0x%x] DCMD=[0x%x]\n", + dma_txbuf_phy_addr, DSADR(tx_dma_channel),DTADR(tx_dma_channel), + DCSR(tx_dma_channel),DCMD(tx_dma_channel) ); + if(panic_sspdev) + { + printk("SSCR0 =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSCR0)) ; + printk("SSCR1 =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSCR1)) ; + printk("SSTO =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSTO)) ; + printk("SSPSP =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSPSP)) ; + printk("SSSR =[0x%x]\n",__raw_readl(panic_sspdev->ssp->mmio_base + SSSR)) ; + } +#endif + + panic_event_handled =1 ; + } + return NOTIFY_OK ; +} + +static struct notifier_block sms_panic_notifier = { + .notifier_call = sms_panic_handler, + .next = NULL, + .priority = 150 /* priority: INT_MAX >= x >= 0 */ +}; + + + + +/*! GPIO functions for PXA3xx +*/ +// obsolete +void pxa3xx_gpio_set_rising_edge_detect (int gpio_id, int dir) +{ +#if 0 + unsigned long flags; + int gpio = mfp_to_gpio(gpio_id); + +// if (gpio >= GPIO_EXP_START) +// { +// return 0; +// } +// spin_lock_irqsave(&gpio_spin_lock, flags); + local_irq_save(flags); + + if ( dir == GPIO_DIR_IN) + GCRER(gpio) =1u << (gpio& 0x1f); + else + GSRER(gpio) =1u << (gpio& 0x1f); + local_irq_restore(flags); +#endif +} + +void pxa3xx_gpio_set_direction(int gpio_id , int dir) +{ +#if 0 + unsigned long flags; + int gpio = mfp_to_gpio(gpio_id); + + local_irq_save(flags); + + if ( dir == GPIO_DIR_IN) + GCDR(gpio) =1u << (gpio& 0x1f); + else + GSDR(gpio) =1u << (gpio& 0x1f); + local_irq_restore(flags); +#endif +} +////////////////////////////////////////////////////////// + +/* physical layer variables */ +/*! global bus data */ +struct spiphy_dev_s { + //struct ssp_dev sspdev; /*!< ssp port configuration */ + struct completion transfer_in_process; + struct spi_device *Smsdevice; + void (*interruptHandler) (void *); + void *intr_context; + struct device *dev; /*!< device model stuff */ + int rx_dma_channel; + int tx_dma_channel; + int rx_buf_len; + int tx_buf_len; +}; + + + + +/*! +invert the endianness of a single 32it integer + +\param[in] u: word to invert + +\return the inverted word +*/ +static inline u32 invert_bo(u32 u) +{ + return ((u & 0xff) << 24) | ((u & 0xff00) << 8) | ((u & 0xff0000) >> 8) + | ((u & 0xff000000) >> 24); +} + +/*! +invert the endianness of a data buffer + +\param[in] buf: buffer to invert +\param[in] len: buffer length + +\return the inverted word +*/ + +static int invert_endianness(char *buf, int len) +{ + int i; + u32 *ptr = (u32 *) buf; + + len = (len + 3) / 4; + for (i = 0; i < len; i++, ptr++) + *ptr = invert_bo(*ptr); + + return 4 * ((len + 3) & (~3)); +} + +/*! Map DMA buffers when request starts + +\return error status +*/ +static unsigned long dma_map_buf(struct spiphy_dev_s *spiphy_dev, char *buf, + int len, int direction) +{ + unsigned long phyaddr; + /* map dma buffers */ + if (!buf) { + PERROR(" NULL buffers to map\n"); + return 0; + } + /* map buffer */ + phyaddr = dma_map_single(spiphy_dev->dev, buf, len, direction); + if (dma_mapping_error(phyaddr)) { + PERROR("exiting with error\n"); + return 0; + } + return phyaddr; +} + +static irqreturn_t spibus_interrupt(int irq, void *context) +{ + struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context; + + u_irq_count ++; + + PDEBUG("INT counter = %d\n", u_irq_count); + + sms_debug("spibus_interrupt\n"); + + if (spiphy_dev->interruptHandler) + spiphy_dev->interruptHandler(spiphy_dev->intr_context); + + return IRQ_HANDLED; + +} + +/*! DMA controller callback - called only on BUS error condition + +\param[in] channel: DMA channel with error +\param[in] data: Unused +\param[in] regs: Unused +\return void +*/ + +//extern dma_addr_t common_buf_end ; + +static void spibus_dma_handler(int channel, void *context) +{ +#if 0 + struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context; + u32 irq_status = DCSR(channel) & DMA_INT_MASK; + +// printk( "recieved interrupt from dma channel %d irq status %x.\n", +// channel, irq_status); + if (irq_status & DCSR_BUSERR) { + printk(KERN_EMERG "bus error!!! resetting channel %d\n", channel); + + DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL; + DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL; + } + DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL; + complete(&spiphy_dev->transfer_in_process); +#endif +} + +void smsspibus_xfer(void *context, unsigned char *txbuf, + unsigned long txbuf_phy_addr, unsigned char *rxbuf, + unsigned long rxbuf_phy_addr, int len) +{ + struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context; + unsigned char *temp = NULL; + int ret; + + //printk(KERN_INFO "smsspibus_xfer \n"); + //printk(KERN_INFO "smsspibus_xfer txbuf = 0x%x\n",txbuf); + //printk(KERN_INFO "smsspibus_xfer rxbuf = 0x%x\n",rxbuf); + //printk(KERN_INFO "smsspibus_xfer len=0x%x\n",len); + + //while (1) + //{ + //mdelay(100); +#if 1 + if (txbuf) + { + // sms_debug("spi write buf[4] = 0x%x buf[5] = 0x%x\n", txbuf[4],txbuf[5]); + ret = spi_write(spiphy_dev->Smsdevice, txbuf, len); + } + +#if 0 + else + { + temp = kmalloc(len,GFP_KERNEL); + if (temp == NULL) + { + sms_err("sms spi write temp malloc fail"); + return -ENOMEM; + } + memset(temp,0xFF,len); + sms_debug("sms spi write temp buf"); + ret = spi_write(spiphy_dev->Smsdevice, temp, len); + } +#endif +// if (ret) + // sms_err(KERN_INFO "smsspibus_xfer spi write ret=0x%x\n",ret); + +// memset (rxbuf, 0xff, 256); + + + if ((rxbuf)&&(len != 16)) + ret = spi_read(spiphy_dev->Smsdevice, rxbuf, len); + + //sms_debug("sms spi read buf=0x%x\n",rxbuf[0]); + //sms_debug("sms spi read buf=0x%x\n",rxbuf[1]); + //sms_debug("sms spi read buf=0x%x\n",rxbuf[2]); + //sms_debug("sms spi read buf=0x%x\n",rxbuf[3]); +// printk(KERN_INFO "after sms spi read buf[0]=0x%x\n",rxbuf[0]); + + // printk(KERN_INFO "sms spi read buf[8]=0x%x\n",rxbuf[8]); + // printk(KERN_INFO "sms spi read buf[9]=0x%x\n",rxbuf[9]); + //} +#else + spi_write_then_read(spiphy_dev->Smsdevice,txbuf,len,rxbuf,len); +#endif + //spi_write_then_read(struct spi_device *spi, const u8 *txbuf, unsigned n_tx, u8 *rxbuf, unsigned n_rx); +#if 0 //hzb 0524 + /* DMA burst is 8 bytes, therefore we need tmp buffer that size. */ + // to support dma 16byte burst size + unsigned long tmp[4]; + //unsigned long tmp[2]; + + unsigned long txdma; + struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context; + unsigned long expire; + int res =0; + + expire = msecs_to_jiffies(200) ; + /* program the controller */ + if (txbuf) + { +// PDEBUG("tx \n"); + invert_endianness(txbuf, len); + } +// else +// PDEBUG("rx \n"); + tmp[0] = -1; + tmp[1] = -1; + tmp[2] = -1; + tmp[3] = -1; + + /* map RX buffer */ + + if (!txbuf) + { + txdma = + dma_map_buf(spiphy_dev, (char *)tmp, sizeof(tmp), + DMA_TO_DEVICE); + tx_len = 0 ; + } + else + { + txdma = txbuf_phy_addr; + tx_len = len ; + } + + init_completion(&spiphy_dev->transfer_in_process); + /* configure DMA Controller */ + DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL; + DSADR(spiphy_dev->rx_dma_channel) = __PREG(SSDR_P(SSP_PORT)); + DTADR(spiphy_dev->rx_dma_channel) = rxbuf_phy_addr; + + + // to support dma 16byte burst size + DCMD(spiphy_dev->rx_dma_channel) = DCMD_INCTRGADDR | DCMD_FLOWSRC + | DCMD_WIDTH4 | DCMD_ENDIRQEN | DMA_BURST_SIZE | len; + + + + rx_dma_channel = spiphy_dev->rx_dma_channel ; + dma_rxbuf_phy_addr = (unsigned int) rxbuf_phy_addr ; + dma_len = len ; +// PDEBUG("rx channel=%d, src=0x%x, dst=0x%x, cmd=0x%x\n", +// spiphy_dev->rx_dma_channel, __PREG(SSDR_P(SSP_PORT)), +// (unsigned int)rxbuf_phy_addr, DCMD(spiphy_dev->rx_dma_channel)); + spiphy_dev->rx_buf_len = len; + + DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL; + DTADR(spiphy_dev->tx_dma_channel) = __PREG(SSDR_P(SSP_PORT)); + + + DSADR(spiphy_dev->tx_dma_channel) = txdma; + + tx_dma_channel = spiphy_dev->tx_dma_channel; + dma_txbuf_phy_addr = (unsigned int) txdma ; + + if (txbuf) { + DCMD(spiphy_dev->tx_dma_channel) = + DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_WIDTH4 + /* | DCMD_ENDIRQEN */ | DMA_BURST_SIZE | len; + spiphy_dev->tx_buf_len = len; + } else { + DCMD(spiphy_dev->tx_dma_channel) = DCMD_FLOWTRG + | DCMD_WIDTH4 /* | DCMD_ENDIRQEN */ |DMA_BURST_SIZE | len; + spiphy_dev->tx_buf_len = 4; + } + +#if 0 + printk("Tx DSADR=[0x%x],DTADR=[0x%x],DCMD=[0x%x],len =[0x%x]\n", + DSADR(spiphy_dev->tx_dma_channel),DTADR(spiphy_dev->tx_dma_channel),DCMD(spiphy_dev->tx_dma_channel),len) ; +#endif +// PDEBUG("tx channel=%d, src=0x%x, dst=0x%x, cmd=0x%x\n", +// spiphy_dev->tx_dma_channel, (unsigned int)txdma, +// __PREG(SSDR_P(SSP_PORT)), DCMD(spiphy_dev->tx_dma_channel)); + /* DALGN - DMA ALIGNMENT REG. */ + if (rxbuf_phy_addr & 0x7) + DALGN |= (1 << spiphy_dev->rx_dma_channel); + else + DALGN &= ~(1 << spiphy_dev->rx_dma_channel); + if (txdma & 0x7) + DALGN |= (1 << spiphy_dev->tx_dma_channel); + else + DALGN &= ~(1 << spiphy_dev->tx_dma_channel); + + /* Start DMA controller */ + //printk( "smsmdtv: Start DMA controller\n"); + DCSR(spiphy_dev->rx_dma_channel) |= DCSR_RUN; + DCSR(spiphy_dev->tx_dma_channel) |= DCSR_RUN; +// printk( "DMA running. wait for completion.\n"); + +//printk( "smsmdtv: before wait_for_completion_timeout\n"); + res = wait_for_completion_timeout(&spiphy_dev->transfer_in_process,expire); + if(!res) + { + printk( "smsmdtv DMA timeout, res=0x%x len =%d\n", res, len); + printk( "smsmdtv DMA reg, 0x%x %x \n",DCSR(spiphy_dev->rx_dma_channel), DCSR(spiphy_dev->tx_dma_channel) ); + DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL; + DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL; + + complete(&spiphy_dev->transfer_in_process); + } +// else + { + //printk( "DMA complete.\n"); + invert_endianness(rxbuf, len); + + if (!txbuf) + PDEBUG("rx[4]:0x%x;[6]:0x%x \n", rxbuf[4], rxbuf[6]); + } +//printk( "smsmdtv: Xfer end\n"); +#endif //hzb 0524 +} + +void smschipreset(void *context) +{ + +} + +static struct ssp_state sms_ssp_state ; + +void smsspibus_ssp_suspend(void* context ) +{ + struct spiphy_dev_s *spiphy_dev ; + printk("entering smsspibus_ssp_suspend\n"); + if(!context) + { + PERROR("smsspibus_ssp_suspend context NULL \n") ; + return ; + } + spiphy_dev = (struct spiphy_dev_s *) context; + + //ssp_flush(&(spiphy_dev->sspdev)) ; + //ssp_save_state(&(spiphy_dev->sspdev) , &sms_ssp_state) ; + //ssp_disable(&(spiphy_dev->sspdev)); + //ssp_exit(&spiphy_dev->sspdev); + free_irq(CMMB_1186_SPIIRQ, spiphy_dev); + + /* release DMA resources */ + //if (spiphy_dev->rx_dma_channel >= 0) + //pxa_free_dma(spiphy_dev->rx_dma_channel); + + //if (spiphy_dev->tx_dma_channel >= 0) + //pxa_free_dma(spiphy_dev->tx_dma_channel); + chip_powerdown(); + +} +static void chip_poweron() +{ +#if 0 +#ifdef CONFIG_MACH_LC6830_PHONE_BOARD_1_0 + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 1); + mdelay(100); + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 1); + mdelay(1); +#elif defined CONFIG_MACH_LC6830_PHONE_BOARD_1_1 + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 1); + mdelay(50); + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO8), 1); + mdelay(200); + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 1); + mdelay(1); +#endif +#endif +} + +static void chip_powerdown() +{ +#if 0 //hzb test +#ifdef CONFIG_MACH_LC6830_PHONE_BOARD_1_0 + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 0); + mdelay(50); + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 0); +#elif defined CONFIG_MACH_LC6830_PHONE_BOARD_1_1 + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO4), 0); + mdelay(100); + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO8), 0); + mdelay(100); + gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO6), 0); + mdelay(1); +#endif +#endif +} + +int smsspibus_ssp_resume(void* context) +{ + int ret; + struct spiphy_dev_s *spiphy_dev ; + u32 mode = 0, flags = 0, psp_flags = 0, speed = 0; + printk("entering smsspibus_ssp_resume\n"); + + if(!context){ + PERROR("smsspibus_ssp_resume context NULL \n"); + return -1; + } + spiphy_dev = (struct spiphy_dev_s *) context; + chip_poweron(); + //ret = ssp_init(&spiphy_dev->sspdev, SSP_PORT, 0); + //if (ret) { + //PERROR("ssp_init failed. error %d", ret); + //} + //GPIOPullUpDown(CMMB_1186_SPIIRQ, IRQT_FALLING); + //err = request_gpio_irq(PT2046_PENIRQ,xpt2046_ts_interrupt,GPIOEdgelFalling,ts_dev); + //ret = request_gpio_irq(CMMB_1186_SPIIRQ, (pFunc)spibus_interrupt, GPIOEdgelRising, spiphy_dev); + if(ret<0){ + printk("siano1186 request irq failed !!\n"); + ret = -EBUSY; + goto fail1; + } + return 0 ; +fail1: + free_irq(CMMB_1186_SPIIRQ,NULL); + return -1 ; +} + + +void *smsspiphy_init(void *context, void (*smsspi_interruptHandler) (void *), + void *intr_context) +{ + int ret; + struct spiphy_dev_s *spiphy_dev; + u32 mode = 0, flags = 0, psp_flags = 0, speed = 0; + + sms_debug("smsspiphy_init\n"); + + spiphy_dev = kmalloc(sizeof(struct spiphy_dev_s), GFP_KERNEL); + if(!spiphy_dev ) + { + printk("spiphy_dev is null in smsspiphy_init\n") ; + return NULL; + } + chip_powerdown(); + spiphy_dev->interruptHandler = smsspi_interruptHandler; + spiphy_dev->intr_context = intr_context; + spiphy_dev->Smsdevice = (struct spi_device*)context; + + GPIOPullUpDown(CMMB_1186_SPIIRQ, IRQT_FALLING); + + ret = request_gpio_irq(CMMB_1186_SPIIRQ, spibus_interrupt, GPIOEdgelRising, spiphy_dev);// + + if(ret<0){ + printk("siano 1186 request irq failed !!\n"); + ret = -EBUSY; + goto fail1; + } + + atomic_notifier_chain_register(&panic_notifier_list,&sms_panic_notifier); + //panic_sspdev = &(spiphy_dev->sspdev) ; + + PDEBUG("exiting\n"); + + return spiphy_dev; + +error_irq: + //if (spiphy_dev->tx_dma_channel >= 0) + //pxa_free_dma(spiphy_dev->tx_dma_channel); + +error_txdma: + //if (spiphy_dev->rx_dma_channel >= 0) + //pxa_free_dma(spiphy_dev->rx_dma_channel); + +error_rxdma: +// ssp_exit(&spiphy_dev->sspdev); +error_sspinit: + //PDEBUG("exiting on error\n"); + printk("exiting on error\n"); +fail1: + free_irq(CMMB_1186_SPIIRQ,NULL); + return 0; +} + +int smsspiphy_deinit(void *context) +{ + struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context; + PDEBUG("entering\n"); + + printk("entering smsspiphy_deinit\n"); + + panic_sspdev = NULL; + atomic_notifier_chain_unregister(&panic_notifier_list, + &sms_panic_notifier); + chip_powerdown(); + PDEBUG("exiting\n"); + return 0; +} + +void smsspiphy_set_config(struct spiphy_dev_s *spiphy_dev, int clock_divider) +{ + //u32 mode, flags, speed, psp_flags = 0; + //ssp_disable(&spiphy_dev->sspdev); + /* clock divisor for this mode. */ + //speed = CLOCK_DIVIDER(clock_divider); + /* 32bit words in the fifo */ + //mode = SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS; + //flags = SPI_RX_FIFO_RFT |SPI_TX_FIFO_TFT | SSCR1_TSRE | + //SSCR1_RSRE | SSCR1_RIE | SSCR1_TRAIL; /* | SSCR1_TIE */ + //ssp_config(&spiphy_dev->sspdev, mode, flags, psp_flags, speed); + //ssp_enable(&spiphy_dev->sspdev); +} + +void prepareForFWDnl(void *context) +{ + struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context; + smsspiphy_set_config(spiphy_dev, 3); + msleep(100); +} + +void fwDnlComplete(void *context, int App) +{ + struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context; + smsspiphy_set_config(spiphy_dev, 1); + msleep(100); +} diff --git a/drivers/cmmb/siano/smsspiphy_rk.c b/drivers/cmmb/siano/smsspiphy_rk.c new file mode 100755 index 000000000000..b61128a2c718 --- /dev/null +++ b/drivers/cmmb/siano/smsspiphy_rk.c @@ -0,0 +1,631 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ +//#define PXA_310_LV + +#include +#include +//#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "smsdbg_prn.h" +#include +#include +#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 + +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); +} -- 2.34.1