add cmmb moudle file directory.
[firefly-linux-kernel-4.4.55.git] / drivers / cmmb / cmmb_memory.c
diff --git a/drivers/cmmb/cmmb_memory.c b/drivers/cmmb/cmmb_memory.c
new file mode 100755 (executable)
index 0000000..f476877
--- /dev/null
@@ -0,0 +1,499 @@
+#include "cmmb_memory.h"\r
+#include "cmmb_class.h"\r
+#include <linux/errno.h>\r
+#include <linux/workqueue.h>\r
+#include <asm/atomic.h>\r
+\r
+#if 1\r
+#define DBGERR(x...)   printk(KERN_INFO x)\r
+#else\r
+#define DBGERR(x...)\r
+#endif\r
+\r
+#if 0\r
+#define DBG(x...)      printk(KERN_INFO x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+struct cmmb_memory CMMB_memo;\r
+static struct cmmb_device* cmmbmemo;\r
+\r
+\r
+static int cmmbmemo_release(struct inode *inode, struct file *file)\r
+{\r
+    struct cmmb_memory *cmmb_memo = (struct cmmb_memory*)file->private_data;\r
+    \r
+    DBG("[CMMB HW]:[memory]: enter cmmb av memory release\n");\r
+    \r
+    mutex_lock(&cmmb_memo->mutex);\r
+    \r
+       cmmb_memo->usr--;\r
+    \r
+       if(cmmb_memo->usr == 0){\r
+        kfree(cmmb_memo->video_buf);\r
+        kfree(cmmb_memo->audio_buf);\r
+        kfree(cmmb_memo->data_buf);\r
+               mutex_unlock(&cmmb_memo->mutex);\r
+        DBG("[CMMB HW]:[memory]: enter cmmb av memory release free buffer\n");\r
+       } else{\r
+               mutex_unlock(&cmmb_memo->mutex);\r
+       }    \r
+    return 0;\r
+}\r
+\r
+//hzb@20100416,ÔÚ´ò¿ªÉ豸µÄʱºòÉêÇë¿Õ¼ä\r
+static int cmmbmemo_open(struct inode * inode, struct file * file)\r
+{\r
+    struct cmmb_memory *cmmbmemo = &CMMB_memo;\r
+    int ret = 0;\r
+    \r
+    DBG("[CMMB HW]:[memory]: enter cmmb memo open\n");\r
+\r
+    if (mutex_lock_interruptible(&cmmbmemo->mutex))\r
+        return -ERESTARTSYS;\r
+    \r
+    cmmbmemo->usr++;\r
+    \r
+    if (cmmbmemo->usr == 1)\r
+    {\r
+        DBG("[CMMB HW]:[memory]:cmmb video buffer malloc\n");\r
+        \r
+        cmmbmemo->video_buf = NULL;\r
+        cmmbmemo->audio_buf = NULL;\r
+        cmmbmemo->data_buf  = NULL;\r
+\r
+        cmmbmemo->video_buf = kmalloc(CMMB_VIDEO_BUFFER_SIZE+1, GFP_KERNEL);\r
+\r
+        if (cmmbmemo->video_buf == NULL){\r
+            ret = - ENOMEM;\r
+            DBGERR("[CMMB HW]:[memory]:[err]: cmmb video buffer malloc fail!!!\n");\r
+            goto kmalloc_fail;\r
+        }\r
+\r
+        cmmbmemo->audio_buf = kmalloc(CMMB_AUDIO_BUFFER_SIZE+1, GFP_KERNEL);\r
+\r
+        if (cmmbmemo->audio_buf == NULL){\r
+            ret = - ENOMEM;\r
+            DBGERR("[CMMB HW]:[memory]:[err]: cmmb audio buffer malloc fail!!!\n");\r
+            goto kmalloc_fail;\r
+        }\r
+\r
+        cmmbmemo->data_buf = kmalloc(1, GFP_KERNEL);\r
+\r
+        if (cmmbmemo->data_buf == NULL){\r
+            ret = - ENOMEM;\r
+            DBGERR("[CMMB HW]:[memory]:[err]: cmmb data buffer malloc fail!!!\n");\r
+            goto kmalloc_fail;\r
+        }\r
+\r
+        //hzb@20100415,init av ring buffers,cmmb need three ring buffers to store the demuxed data\r
+        cmmb_ringbuffer_init(&cmmbmemo->buffer_Video, cmmbmemo->video_buf, CMMB_VIDEO_BUFFER_SIZE);  //init video ring buffer\r
+        cmmb_ringbuffer_init(&cmmbmemo->buffer_Audio, cmmbmemo->audio_buf, CMMB_AUDIO_BUFFER_SIZE);  //init audio ring buffer\r
+        cmmb_ringbuffer_init(&cmmbmemo->buffer_Data,  cmmbmemo->data_buf,  1);   //init data ring buffer\r
+\r
+        cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+        cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
+    }\r
+    file->private_data = cmmbmemo;  //hzb@20100415,store the cmmbmemo struct in the file private data \r
+    mutex_unlock(&cmmbmemo->mutex);    \r
+    return ret;\r
+        \r
+kmalloc_fail:\r
+    kfree(cmmbmemo->video_buf);\r
+    kfree(cmmbmemo->audio_buf);\r
+    kfree(cmmbmemo->data_buf);\r
+    mutex_unlock(&cmmbmemo->mutex);    \r
+    return ret;        \r
+}\r
+
+\r
+static ssize_t cmmbmemo_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)\r
+{\r
+    struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
+    ssize_t avail_V, avail_A, avail_D;\r
+    ssize_t ret;\r
+    \r
+    DBG("[CMMB HW]:[memory]:enter cmmb memory read\n");\r
+    \r
+    if (cmmbmemo->r_datatype == CMMB_VIDEO_TYPE){\r
+#if 0         \r
+        DECLARE_WAITQUEUE(wait, current);\r
+        for(;;){\r
+            avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+             \r
+            if (avail_V < count){          \r
+                add_wait_queue(&cmmbmemo->buffer_Video.queue, &wait);\r
+                __set_current_state(TASK_INTERRUPTIBLE);\r
+                schedule();\r
+                remove_wait_queue(&cmmbmemo->buffer_Video.queue, &wait);\r
+                if (signal_pending(current)){\r
+                   ret = -ERESTARTSYS;\r
+                   goto out2;\r
+                }\r
+            }\r
+        }\r
+#else\r
+#if 0\r
+        avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+        while (avail_V < count){\r
+            DBG("[CMMB HW]:[memory]:cmmb memory read video data sleep!!\n");\r
+            spin_lock(cmmbmemo->buffer_Video.lock);\r
+            cmmbmemo->buffer_Video.condition = 0;\r
+            spin_unlock(cmmbmemo->buffer_Video.lock);\r
+            if (wait_event_interruptible(cmmbmemo->buffer_Video.queue, cmmbmemo->buffer_Video.condition))\r
+                return -ERESTARTSYS;\r
+            \r
+            avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+            DBG("[CMMB HW]:[memory]:cmmb memory read video data awake\n");\r
+        }\r
+#endif \r
+           avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+           if (avail_V < count)  \r
+               return 0;     \r
+#endif          \r
+        ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Video, buf, count, 1);   
+     \r
+        DBG("[CMMB HW]:[memory]:cmmb memory video read ret = 0x%x\n",ret);\r
+    }else if (cmmbmemo->r_datatype == CMMB_AUDIO_TYPE){\r
+#if 0\r
+        DECLARE_WAITQUEUE(wait, current);\r
+        for(;;){\r
+            avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
+            if (avail_A < count){\r
+                add_wait_queue(&cmmbmemo->buffer_Audio.queue, &wait);\r
+                __set_current_state(TASK_INTERRUPTIBLE);\r
+                schedule();\r
+                remove_wait_queue(&cmmbmemo->buffer_Audio.queue, &wait);\r
+                if (signal_pending(current)){\r
+                    ret = -ERESTARTSYS;\r
+                    goto out2;\r
+                }\r
+            }\r
+        }\r
+#else\r
+#if 0\r
+        avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
+        while (avail_A < count){\r
+            DBG("[CMMB HW]:[memory]:cmmb memory read audio data sleep!!\n");\r
+            spin_lock(cmmbmemo->buffer_Audio.lock);\r
+            cmmbmemo->buffer_Audio.condition = 0;\r
+            spin_unlock(cmmbmemo->buffer_Audio.lock);\r
+            if (wait_event_interruptible(cmmbmemo->buffer_Audio.queue, cmmbmemo->buffer_Audio.condition))\r
+                return -ERESTARTSYS;\r
+            \r
+            avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
+            DBG("[CMMB HW]:[memory]:cmmb memory read audio data awake\n");\r
+        }\r
+#endif\r
+               avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);  \r
+               if (avail_A < count)  \r
+                       return 0;    \r
+#endif\r
+        ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Audio, buf, count, 1);\r
+    }else if(cmmbmemo->r_datatype == CMMB_DATA_TYPE){\r
+ #if 0   \r
+        DECLARE_WAITQUEUE(wait, current);\r
+        for(;;){\r
+           avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
+           if (avail_D < count){\r
+               add_wait_queue(&cmmbmemo->buffer_Data.queue, &wait);\r
+               __set_current_state(TASK_INTERRUPTIBLE);\r
+               schedule();\r
+               remove_wait_queue(&cmmbmemo->buffer_Data.queue, &wait);\r
+               if (signal_pending(current)){\r
+                   ret = -ERESTARTSYS;\r
+                   goto out2;\r
+               }\r
+           }\r
+        }\r
+#else\r
+#if 0\r
+        avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
+        while (avail_D < count){\r
+        DBG("[CMMB HW]:[memory]:cmmb memory read data sleep!!\n");\r
+        spin_lock(cmmbmemo->buffer_Data.lock);\r
+        cmmbmemo->buffer_Data.condition = 0;\r
+        spin_unlock(cmmbmemo->buffer_Data.lock);\r
+        if (wait_event_interruptible(cmmbmemo->buffer_Data.queue, cmmbmemo->buffer_Data.condition))\r
+            return -ERESTARTSYS;\r
+        \r
+        avail_D= cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
+        DBG("[CMMB HW]:[memory]:cmmb memory read data awake\n");\r
+        }\r
+#endif\r
+               avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);  \r
+               if (avail_D < count)  \r
+                       return 0;               \r
+#endif\r
+        ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Data, buf, count, 1);\r
+    }\r
+    \r
+out2:\r
+    cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
+    return ret;;\r
+}\r
+\r
+\r
+\r
+static ssize_t cmmbmemo_write(struct file *file, char __user *buf, size_t count,loff_t *ppos)\r
+{\r
+    struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
+    ssize_t free_V, free_A, free_D;\r
+    ssize_t ret;\r
+    static int loop = 0;\r
+    \r
+    DBG("[CMMB HW]:[memory]:enter cmmbdemux_write\n");\r
+    \r
+    if (cmmbmemo->w_datatype == CMMB_VIDEO_TYPE){\r
+        \r
+        free_V = cmmb_ringbuffer_free(&cmmbmemo->buffer_Video);\r
+        if (free_V >= count){\r
+           ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Video, buf, count);\r
+        }
+        //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+        spin_lock(cmmbmemo->buffer_Video.lock);\r
+        cmmbmemo->buffer_Video.condition = 1;\r
+        spin_unlock(cmmbmemo->buffer_Video.lock);\r
+        wake_up_interruptible(&cmmbmemo->buffer_Video.queue);\r
+    }else if (cmmbmemo->w_datatype == CMMB_AUDIO_TYPE){\r
+        free_A = cmmb_ringbuffer_free(&cmmbmemo->buffer_Audio);\r
+        if (free_A >= count){\r
+           ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Audio, buf, count);\r
+        }\r
+        //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+        spin_lock(cmmbmemo->buffer_Audio.lock);\r
+        cmmbmemo->buffer_Audio.condition = 1;\r
+        spin_unlock(cmmbmemo->buffer_Audio.lock);\r
+        wake_up_interruptible(&cmmbmemo->buffer_Audio.queue);\r
+    }else if(cmmbmemo->w_datatype == CMMB_DATA_TYPE){\r
+        free_D = cmmb_ringbuffer_free(&cmmbmemo->buffer_Data);\r
+        if (free_D >= count){\r
+           ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Data, buf, count);\r
+        }\r
+        //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+        spin_lock(cmmbmemo->buffer_Data.lock);\r
+        cmmbmemo->buffer_Data.condition = 1;\r
+        spin_unlock(cmmbmemo->buffer_Data.lock);\r
+        wake_up_interruptible(&cmmbmemo->buffer_Data.queue);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+\r
+int cmmbmemo_valueinit(struct file *file)\r
+{\r
+    struct cmmb_memory *cmmbmemo = file->private_data;\r
+    int ret = 0;\r
+\r
+    DBG("[CMMB HW]:[memory]: enter cmmb memo open\n");\r
+\r
+    cmmbmemo->video_buf = NULL;\r
+    cmmbmemo->audio_buf = NULL;\r
+    cmmbmemo->data_buf  = NULL;\r
+\r
+    cmmbmemo->video_buf = kzalloc(CMMB_VIDEO_BUFFER_SIZE+1, GFP_KERNEL);\r
+\r
+    if (cmmbmemo->video_buf == NULL){\r
+        ret = - ENOMEM;\r
+        DBGERR("[CMMB HW]:[memory]:[err]: cmmb video buffer malloc fail!!!\n");\r
+        goto kmalloc_fail;\r
+    }\r
+\r
+    cmmbmemo->audio_buf = kzalloc(CMMB_AUDIO_BUFFER_SIZE+1, GFP_KERNEL);\r
+\r
+    if (cmmbmemo->audio_buf == NULL){\r
+        ret = - ENOMEM;\r
+        DBGERR("[CMMB HW]:[memory]:[err]: cmmb audio buffer malloc fail!!!\n");\r
+        goto kmalloc_fail;\r
+    }\r
+\r
+    cmmbmemo->data_buf = kzalloc(1, GFP_KERNEL);\r
+\r
+    if (cmmbmemo->data_buf == NULL){\r
+        ret = - ENOMEM;\r
+        DBGERR("[CMMB HW]:[memory]:[err]: cmmb data buffer malloc fail!!!\n");\r
+        goto kmalloc_fail;\r
+    }\r
+\r
+    //hzb@20100415,init av ring buffers,cmmb need three ring buffers to store the demuxed data\r
+    cmmb_ringbuffer_init(&cmmbmemo->buffer_Video, cmmbmemo->video_buf, CMMB_VIDEO_BUFFER_SIZE);  //init video ring buffer\r
+    cmmb_ringbuffer_init(&cmmbmemo->buffer_Audio, cmmbmemo->audio_buf, CMMB_AUDIO_BUFFER_SIZE);  //init audio ring buffer\r
+    cmmb_ringbuffer_init(&cmmbmemo->buffer_Data,  cmmbmemo->data_buf,  1);   //init data ring buffer\r
+\r
+    cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
+    cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
+\r
+    return ret;\r
+\r
+kmalloc_fail:\r
+    kfree(cmmbmemo->video_buf);\r
+    kfree(cmmbmemo->audio_buf);\r
+    kfree(cmmbmemo->data_buf);\r
+    return ret;   \r
+}\r
+\r
+static long cmmbmemo_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+    struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
+    long ret = 0;\r
+    \r
+    DBG("[CMMB HW]:[memory]:enter cmmbdemux_ioctl\n");\r
+\r
+    switch (cmd){\r
+           case CMMB_MEMO_WRITE:{\r
+            cmmbmemo->w_datatype = arg;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_MEMO_READ:{\r
+            cmmbmemo->r_datatype = arg;\r
+        }\r
+        break;\r
+\r
+        case CMMB_MEMO_FLUSH_ONE:{\r
+            if (arg == CMMB_VIDEO_TYPE){\r
+                cmmb_ringbuffer_flush(&cmmbmemo->buffer_Video);\r
+            }else if (arg == CMMB_AUDIO_TYPE){\r
+                cmmb_ringbuffer_flush(&cmmbmemo->buffer_Audio);\r
+            }else if (arg == CMMB_DATA_TYPE){\r
+                cmmb_ringbuffer_flush(&cmmbmemo->buffer_Data);\r
+            }else{\r
+                ret = - EINVAL;\r
+            }\r
+        }\r
+        break;\r
+       \r
+        case CMMB_MEMO_FLUSH_ALL:{\r
+            cmmb_ringbuffer_flush(&cmmbmemo->buffer_Video);\r
+            cmmb_ringbuffer_flush(&cmmbmemo->buffer_Audio);\r
+            cmmb_ringbuffer_flush(&cmmbmemo->buffer_Data);\r
+        }\r
+        break;\r
+        \r
+        case CMMB_MEMO_INIT:{\r
+            return cmmbmemo_valueinit(file);\r
+        }\r
+        break;\r
+\r
+        case CMMB_SET_VIDEO_TYPE:{\r
+            cmmbmemo->videotype = arg;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_SET_AUDIO_TYPE:{\r
+            cmmbmemo->audiotype = arg;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_SET_AUDIO_SAMPLE:{\r
+            cmmbmemo->audiosample = arg;\r
+        }\r
+        break;\r
+\r
+        case CMMB_GET_VIDEO_TYPE:{\r
+            return cmmbmemo->videotype;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_GET_AUDIO_TYPE:{\r
+            return cmmbmemo->videotype;\r
+        }\r
+        break;\r
+        \r
+        case CMMB_GET_AUDIO_SAMPLE:{\r
+            return cmmbmemo->audiosample;\r
+        }\r
+        break;\r
+\r
+        case CMMB_GET_BUFF_FREE:{\r
+            if (arg == CMMB_VIDEO_TYPE){\r
+                ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Video);\r
+            }else if (arg == CMMB_AUDIO_TYPE){\r
+                ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Audio);\r
+            }else if (arg == CMMB_DATA_TYPE){\r
+                ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Data);\r
+            }else{\r
+                ret = - EINVAL;\r
+            }\r
+        }\r
+        break;\r
+\r
+        case CMMB_GET_BUFF_AVAIL:{\r
+            if (arg == CMMB_VIDEO_TYPE){\r
+                ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
+            }else if (arg == CMMB_AUDIO_TYPE){\r
+                ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
+            }else if (arg == CMMB_DATA_TYPE){\r
+                ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
+            }else{\r
+                ret = - EINVAL;\r
+            }\r
+        }\r
+        break;\r
+        \r
+        default:\r
+            ;\r
+        break;\r
+    }\r
+    return ret;\r
+}\r
+\r
+static unsigned int cmmbmemo_poll(struct file *file, struct poll_table_struct *wait)\r
+{\r
+    struct cmmb_demux *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
+    unsigned int mask = 0;\r
+\r
+    DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
+    \r
+    //2todo memo poll, now doing nothing\r
+  \r
+    return mask;\r
+}\r
+\r
+\r
+static int cmmbmemo_mmap(struct file *file, struct vm_area_struct *vma)\r
+{\r
+    //2 todo memo mmmap, now doing nothing\r
+    DBG("[CMMB HW]:[memory]:enter cmmbdemux_ioctl\n");\r
+    return 0;\r
+}\r
+\r
+\r
+struct file_operations cmmbmemeo_fops = \r
+{\r
+    .open  = cmmbmemo_open,\r
+    .release = cmmbmemo_release,    \r
+    .read  = cmmbmemo_read,\r
+    .write = cmmbmemo_write,\r
+    .mmap  = cmmbmemo_mmap,\r
+    .poll  = cmmbmemo_poll,\r
+    .unlocked_ioctl = cmmbmemo_ioctl,\r
+};\r
+\r
+static int __init cmmbmemo_init(void)\r
+{\r
+    int res;\r
+    \r
+    DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
+       res =cmmb_register_device(&CMMB_adapter,&cmmbmemo, &cmmbmemeo_fops, NULL, CMMB_DEVICE_MEMO,"cmmb_memo");\r
+    mutex_init(&CMMB_memo.mutex);\r
+    CMMB_memo.usr = 0;\r
+    return res;\r
+}\r
+\r
+static void __exit cmmbmemo_exit(void)\r
+{\r
+    DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
+    cmmb_unregister_device(cmmbmemo);\r
+    //mutex_destroy(mutex);\r
+}\r
+\r
+module_init(cmmbmemo_init);\r
+module_exit(cmmbmemo_exit);\r
+\r
+MODULE_DESCRIPTION("CMMB demodulator general driver");\r
+MODULE_AUTHOR("HT,HZB,HH,LW");\r
+MODULE_LICENSE("GPL");\r
+\r