Merge remote branch 'linux-2.6.32.y/master' into develop
[firefly-linux-kernel-4.4.55.git] / drivers / cmmb / cmmb_memory.c
1 #include "cmmb_memory.h"\r
2 #include "cmmb_class.h"\r
3 #include <linux/errno.h>\r
4 #include <linux/workqueue.h>\r
5 #include <asm/atomic.h>\r
6 #include <linux/vmalloc.h> \r
7 #if 1\r
8 #define DBGERR(x...)    printk(KERN_INFO x)\r
9 #else\r
10 #define DBGERR(x...)\r
11 #endif\r
12 \r
13 #if 0\r
14 #define DBG(x...)       printk(KERN_INFO x)\r
15 #else\r
16 #define DBG(x...)\r
17 #endif\r
18 \r
19 struct cmmb_memory CMMB_memo;\r
20 static struct cmmb_device* cmmbmemo;\r
21 \r
22 \r
23 static int cmmbmemo_release(struct inode *inode, struct file *file)\r
24 {\r
25     struct cmmb_memory *cmmb_memo = (struct cmmb_memory*)file->private_data;\r
26     \r
27     DBG("[CMMB HW]:[memory]: enter cmmb av memory release\n");\r
28     \r
29     mutex_lock(&cmmb_memo->mutex);\r
30     \r
31         cmmb_memo->usr--;\r
32     \r
33         if(cmmb_memo->usr == 0){\r
34         vfree(cmmb_memo->video_buf);\r
35         vfree(cmmb_memo->audio_buf);\r
36         vfree(cmmb_memo->data_buf);\r
37                 mutex_unlock(&cmmb_memo->mutex);\r
38         DBG("[CMMB HW]:[memory]: enter cmmb av memory release free buffer\n");\r
39         } else{\r
40                 mutex_unlock(&cmmb_memo->mutex);\r
41         }    \r
42     return 0;\r
43 }\r
44 \r
45 //hzb@20100416,ÔÚ´ò¿ªÉ豸µÄʱºòÉêÇë¿Õ¼ä\r
46 static int cmmbmemo_open(struct inode * inode, struct file * file)\r
47 {\r
48     struct cmmb_memory *cmmbmemo = &CMMB_memo;\r
49     int ret = 0;\r
50     \r
51     DBG("[CMMB HW]:[memory]: enter cmmb memo open\n");\r
52 \r
53     if (mutex_lock_interruptible(&cmmbmemo->mutex))\r
54         return -ERESTARTSYS;\r
55     \r
56     cmmbmemo->usr++;\r
57     \r
58     if (cmmbmemo->usr == 1)\r
59     {\r
60         DBG("[CMMB HW]:[memory]:cmmb video buffer malloc\n");\r
61         \r
62         cmmbmemo->video_buf = NULL;\r
63         cmmbmemo->audio_buf = NULL;\r
64         cmmbmemo->data_buf  = NULL;\r
65 \r
66         //cmmbmemo->video_buf = vmalloc(CMMB_VIDEO_BUFFER_SIZE+1, GFP_KERNEL);\r
67         cmmbmemo->video_buf   = vmalloc(CMMB_VIDEO_BUFFER_SIZE+1);\r
68 \r
69         if (cmmbmemo->video_buf == NULL){\r
70             ret = - ENOMEM;\r
71             DBGERR("[CMMB HW]:[memory]:[err]: cmmb video buffer malloc fail!!!\n");\r
72             goto kmalloc_fail;\r
73         }\r
74 \r
75         //cmmbmemo->audio_buf = vmalloc(CMMB_AUDIO_BUFFER_SIZE+1, GFP_KERNEL);\r
76         cmmbmemo->audio_buf = vmalloc(CMMB_AUDIO_BUFFER_SIZE+1);\r
77         \r
78         \r
79         if (cmmbmemo->audio_buf == NULL){\r
80             ret = - ENOMEM;\r
81             DBGERR("[CMMB HW]:[memory]:[err]: cmmb audio buffer malloc fail!!!\n");\r
82             goto kmalloc_fail;\r
83         }\r
84 \r
85         cmmbmemo->data_buf = vmalloc(1);\r
86 \r
87         if (cmmbmemo->data_buf == NULL){\r
88             ret = - ENOMEM;\r
89             DBGERR("[CMMB HW]:[memory]:[err]: cmmb data buffer malloc fail!!!\n");\r
90             goto kmalloc_fail;\r
91         }\r
92 \r
93         //hzb@20100415,init av ring buffers,cmmb need three ring buffers to store the demuxed data\r
94         cmmb_ringbuffer_init(&cmmbmemo->buffer_Video, cmmbmemo->video_buf, CMMB_VIDEO_BUFFER_SIZE);  //init video ring buffer\r
95         cmmb_ringbuffer_init(&cmmbmemo->buffer_Audio, cmmbmemo->audio_buf, CMMB_AUDIO_BUFFER_SIZE);  //init audio ring buffer\r
96         cmmb_ringbuffer_init(&cmmbmemo->buffer_Data,  cmmbmemo->data_buf,  1);   //init data ring buffer\r
97 \r
98         cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
99         cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
100     }\r
101     file->private_data = cmmbmemo;  //hzb@20100415,store the cmmbmemo struct in the file private data \r
102     mutex_unlock(&cmmbmemo->mutex);    \r
103     return ret;\r
104         \r
105 kmalloc_fail:\r
106     vfree(cmmbmemo->video_buf);\r
107     vfree(cmmbmemo->audio_buf);\r
108     vfree(cmmbmemo->data_buf);\r
109     mutex_unlock(&cmmbmemo->mutex);    \r
110     return ret;        \r
111 }\r
112
113 \r
114 static ssize_t cmmbmemo_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)\r
115 {\r
116     struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
117     ssize_t avail_V, avail_A, avail_D;\r
118     ssize_t ret;\r
119     \r
120     DBG("[CMMB HW]:[memory]:enter cmmb memory read\n");\r
121     \r
122     if (cmmbmemo->r_datatype == CMMB_VIDEO_TYPE){\r
123 #if 0         \r
124         DECLARE_WAITQUEUE(wait, current);\r
125         for(;;){\r
126             avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
127              \r
128             if (avail_V < count){          \r
129                 add_wait_queue(&cmmbmemo->buffer_Video.queue, &wait);\r
130                 __set_current_state(TASK_INTERRUPTIBLE);\r
131                 schedule();\r
132                 remove_wait_queue(&cmmbmemo->buffer_Video.queue, &wait);\r
133                 if (signal_pending(current)){\r
134                    ret = -ERESTARTSYS;\r
135                    goto out2;\r
136                 }\r
137             }\r
138         }\r
139 #else\r
140 #if 0\r
141         avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
142         while (avail_V < count){\r
143             DBG("[CMMB HW]:[memory]:cmmb memory read video data sleep!!\n");\r
144             spin_lock(cmmbmemo->buffer_Video.lock);\r
145             cmmbmemo->buffer_Video.condition = 0;\r
146             spin_unlock(cmmbmemo->buffer_Video.lock);\r
147             if (wait_event_interruptible(cmmbmemo->buffer_Video.queue, cmmbmemo->buffer_Video.condition))\r
148                 return -ERESTARTSYS;\r
149             \r
150             avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
151             DBG("[CMMB HW]:[memory]:cmmb memory read video data awake\n");\r
152         }\r
153 #endif \r
154             avail_V = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
155             if (avail_V < count)  \r
156                 return 0;     \r
157 #endif          \r
158         ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Video, buf, count, 1);   
159      \r
160         DBG("[CMMB HW]:[memory]:cmmb memory video read ret = 0x%x\n",ret);\r
161     }else if (cmmbmemo->r_datatype == CMMB_AUDIO_TYPE){\r
162 #if 0\r
163         DECLARE_WAITQUEUE(wait, current);\r
164         for(;;){\r
165             avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
166             if (avail_A < count){\r
167                 add_wait_queue(&cmmbmemo->buffer_Audio.queue, &wait);\r
168                 __set_current_state(TASK_INTERRUPTIBLE);\r
169                 schedule();\r
170                 remove_wait_queue(&cmmbmemo->buffer_Audio.queue, &wait);\r
171                 if (signal_pending(current)){\r
172                     ret = -ERESTARTSYS;\r
173                     goto out2;\r
174                 }\r
175             }\r
176         }\r
177 #else\r
178 #if 0\r
179         avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
180         while (avail_A < count){\r
181             DBG("[CMMB HW]:[memory]:cmmb memory read audio data sleep!!\n");\r
182             spin_lock(cmmbmemo->buffer_Audio.lock);\r
183             cmmbmemo->buffer_Audio.condition = 0;\r
184             spin_unlock(cmmbmemo->buffer_Audio.lock);\r
185             if (wait_event_interruptible(cmmbmemo->buffer_Audio.queue, cmmbmemo->buffer_Audio.condition))\r
186                 return -ERESTARTSYS;\r
187             \r
188             avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
189             DBG("[CMMB HW]:[memory]:cmmb memory read audio data awake\n");\r
190         }\r
191 #endif\r
192                 avail_A = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);  \r
193                 if (avail_A < count)  \r
194                         return 0;    \r
195 #endif\r
196         ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Audio, buf, count, 1);\r
197     }else if(cmmbmemo->r_datatype == CMMB_DATA_TYPE){\r
198  #if 0   \r
199         DECLARE_WAITQUEUE(wait, current);\r
200         for(;;){\r
201            avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
202            if (avail_D < count){\r
203                add_wait_queue(&cmmbmemo->buffer_Data.queue, &wait);\r
204                __set_current_state(TASK_INTERRUPTIBLE);\r
205                schedule();\r
206                remove_wait_queue(&cmmbmemo->buffer_Data.queue, &wait);\r
207                if (signal_pending(current)){\r
208                    ret = -ERESTARTSYS;\r
209                    goto out2;\r
210                }\r
211            }\r
212         }\r
213 #else\r
214 #if 0\r
215         avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
216         while (avail_D < count){\r
217         DBG("[CMMB HW]:[memory]:cmmb memory read data sleep!!\n");\r
218         spin_lock(cmmbmemo->buffer_Data.lock);\r
219         cmmbmemo->buffer_Data.condition = 0;\r
220         spin_unlock(cmmbmemo->buffer_Data.lock);\r
221         if (wait_event_interruptible(cmmbmemo->buffer_Data.queue, cmmbmemo->buffer_Data.condition))\r
222             return -ERESTARTSYS;\r
223         \r
224         avail_D= cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
225         DBG("[CMMB HW]:[memory]:cmmb memory read data awake\n");\r
226         }\r
227 #endif\r
228                 avail_D = cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);  \r
229                 if (avail_D < count)  \r
230                         return 0;               \r
231 #endif\r
232         ret = cmmb_ringbuffer_read(&cmmbmemo->buffer_Data, buf, count, 1);\r
233     }\r
234     \r
235 out2:\r
236     cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
237     return ret;;\r
238 }\r
239 \r
240 \r
241 \r
242 static ssize_t cmmbmemo_write(struct file *file, char __user *buf, size_t count,loff_t *ppos)\r
243 {\r
244     struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
245     ssize_t free_V, free_A, free_D;\r
246     ssize_t ret;\r
247     static int loop = 0;\r
248     \r
249     DBG("[CMMB HW]:[memory]:enter cmmbdemux_write\n");\r
250     \r
251     if (cmmbmemo->w_datatype == CMMB_VIDEO_TYPE){\r
252         \r
253         free_V = cmmb_ringbuffer_free(&cmmbmemo->buffer_Video);\r
254         if (free_V >= count){\r
255            ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Video, buf, count);\r
256         }
257         //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
258 #if 0\r
259         spin_lock(cmmbmemo->buffer_Video.lock);\r
260         cmmbmemo->buffer_Video.condition = 1;\r
261         spin_unlock(cmmbmemo->buffer_Video.lock);\r
262         wake_up_interruptible(&cmmbmemo->buffer_Video.queue);\r
263 #endif\r
264     }else if (cmmbmemo->w_datatype == CMMB_AUDIO_TYPE){\r
265         free_A = cmmb_ringbuffer_free(&cmmbmemo->buffer_Audio);\r
266         if (free_A >= count){\r
267            ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Audio, buf, count);\r
268         }\r
269         //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
270 #if 0\r
271         spin_lock(cmmbmemo->buffer_Audio.lock);\r
272         cmmbmemo->buffer_Audio.condition = 1;\r
273         spin_unlock(cmmbmemo->buffer_Audio.lock);\r
274 #endif\r
275         //wake_up_interruptible(&cmmbmemo->buffer_Audio.queue);\r
276     }else if(cmmbmemo->w_datatype == CMMB_DATA_TYPE){\r
277         free_D = cmmb_ringbuffer_free(&cmmbmemo->buffer_Data);\r
278         if (free_D >= count){\r
279            ret = cmmb_ringbuffer_write(&cmmbmemo->buffer_Data, buf, count);\r
280         }\r
281         //cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
282 #if 0\r
283         spin_lock(cmmbmemo->buffer_Data.lock);\r
284         cmmbmemo->buffer_Data.condition = 1;\r
285         spin_unlock(cmmbmemo->buffer_Data.lock);\r
286 #endif\r
287         //wake_up_interruptible(&cmmbmemo->buffer_Data.queue);\r
288     }\r
289 \r
290     return ret;\r
291 }\r
292 \r
293 \r
294 int cmmbmemo_valueinit(struct file *file)\r
295 {\r
296     struct cmmb_memory *cmmbmemo = file->private_data;\r
297     int ret = 0;\r
298 \r
299     DBG("[CMMB HW]:[memory]: enter cmmb memo open\n");\r
300 \r
301     cmmbmemo->video_buf = NULL;\r
302     cmmbmemo->audio_buf = NULL;\r
303     cmmbmemo->data_buf  = NULL;\r
304 \r
305     cmmbmemo->video_buf = kzalloc(CMMB_VIDEO_BUFFER_SIZE+1, GFP_KERNEL);\r
306 \r
307     if (cmmbmemo->video_buf == NULL){\r
308         ret = - ENOMEM;\r
309         DBGERR("[CMMB HW]:[memory]:[err]: cmmb video buffer malloc fail!!!\n");\r
310         goto kmalloc_fail;\r
311     }\r
312 \r
313     cmmbmemo->audio_buf = kzalloc(CMMB_AUDIO_BUFFER_SIZE+1, GFP_KERNEL);\r
314 \r
315     if (cmmbmemo->audio_buf == NULL){\r
316         ret = - ENOMEM;\r
317         DBGERR("[CMMB HW]:[memory]:[err]: cmmb audio buffer malloc fail!!!\n");\r
318         goto kmalloc_fail;\r
319     }\r
320 \r
321     cmmbmemo->data_buf = kzalloc(1, GFP_KERNEL);\r
322 \r
323     if (cmmbmemo->data_buf == NULL){\r
324         ret = - ENOMEM;\r
325         DBGERR("[CMMB HW]:[memory]:[err]: cmmb data buffer malloc fail!!!\n");\r
326         goto kmalloc_fail;\r
327     }\r
328 \r
329     //hzb@20100415,init av ring buffers,cmmb need three ring buffers to store the demuxed data\r
330     cmmb_ringbuffer_init(&cmmbmemo->buffer_Video, cmmbmemo->video_buf, CMMB_VIDEO_BUFFER_SIZE);  //init video ring buffer\r
331     cmmb_ringbuffer_init(&cmmbmemo->buffer_Audio, cmmbmemo->audio_buf, CMMB_AUDIO_BUFFER_SIZE);  //init audio ring buffer\r
332     cmmb_ringbuffer_init(&cmmbmemo->buffer_Data,  cmmbmemo->data_buf,  1);   //init data ring buffer\r
333 \r
334     cmmbmemo->w_datatype = CMMB_NULL_TYPE;\r
335     cmmbmemo->r_datatype = CMMB_NULL_TYPE;\r
336 \r
337     return ret;\r
338 \r
339 kmalloc_fail:\r
340     kfree(cmmbmemo->video_buf);\r
341     kfree(cmmbmemo->audio_buf);\r
342     kfree(cmmbmemo->data_buf);\r
343     return ret;   \r
344 }\r
345 \r
346 static long cmmbmemo_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
347 {\r
348     struct cmmb_memory *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
349     long ret = 0;\r
350     \r
351     DBG("[CMMB HW]:[memory]:enter cmmbdemux_ioctl\n");\r
352 \r
353     switch (cmd){\r
354             case CMMB_MEMO_WRITE:{\r
355             cmmbmemo->w_datatype = arg;\r
356         }\r
357         break;\r
358         \r
359         case CMMB_MEMO_READ:{\r
360             cmmbmemo->r_datatype = arg;\r
361         }\r
362         break;\r
363 \r
364         case CMMB_MEMO_FLUSH_ONE:{\r
365             if (arg == CMMB_VIDEO_TYPE){\r
366                 cmmb_ringbuffer_flush(&cmmbmemo->buffer_Video);\r
367             }else if (arg == CMMB_AUDIO_TYPE){\r
368                 cmmb_ringbuffer_flush(&cmmbmemo->buffer_Audio);\r
369             }else if (arg == CMMB_DATA_TYPE){\r
370                 cmmb_ringbuffer_flush(&cmmbmemo->buffer_Data);\r
371             }else{\r
372                 ret = - EINVAL;\r
373             }\r
374         }\r
375         break;\r
376        \r
377         case CMMB_MEMO_FLUSH_ALL:{\r
378             cmmb_ringbuffer_flush(&cmmbmemo->buffer_Video);\r
379             cmmb_ringbuffer_flush(&cmmbmemo->buffer_Audio);\r
380             cmmb_ringbuffer_flush(&cmmbmemo->buffer_Data);\r
381         }\r
382         break;\r
383         \r
384         case CMMB_MEMO_INIT:{\r
385             return cmmbmemo_valueinit(file);\r
386         }\r
387         break;\r
388 \r
389         case CMMB_SET_VIDEO_TYPE:{\r
390             cmmbmemo->videotype = arg;\r
391         }\r
392         break;\r
393         \r
394         case CMMB_SET_AUDIO_TYPE:{\r
395             cmmbmemo->audiotype = arg;\r
396         }\r
397         break;\r
398         \r
399         case CMMB_SET_AUDIO_SAMPLE:{\r
400             cmmbmemo->audiosample = arg;\r
401         }\r
402         break;\r
403 \r
404         case CMMB_GET_VIDEO_TYPE:{\r
405             return cmmbmemo->videotype;\r
406         }\r
407         break;\r
408         \r
409         case CMMB_GET_AUDIO_TYPE:{\r
410             return cmmbmemo->audiotype;\r
411         }\r
412         break;\r
413         \r
414         case CMMB_GET_AUDIO_SAMPLE:{\r
415             return cmmbmemo->audiosample;\r
416         }\r
417         break;\r
418 \r
419         case CMMB_GET_BUFF_FREE:{\r
420             if (arg == CMMB_VIDEO_TYPE){\r
421                 ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Video);\r
422             }else if (arg == CMMB_AUDIO_TYPE){\r
423                 ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Audio);\r
424             }else if (arg == CMMB_DATA_TYPE){\r
425                 ret = (long)cmmb_ringbuffer_free(&cmmbmemo->buffer_Data);\r
426             }else{\r
427                 ret = - EINVAL;\r
428             }\r
429         }\r
430         break;\r
431 \r
432         case CMMB_GET_BUFF_AVAIL:{\r
433             if (arg == CMMB_VIDEO_TYPE){\r
434                 ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Video);\r
435             }else if (arg == CMMB_AUDIO_TYPE){\r
436                 ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Audio);\r
437             }else if (arg == CMMB_DATA_TYPE){\r
438                 ret = (long)cmmb_ringbuffer_avail(&cmmbmemo->buffer_Data);\r
439             }else{\r
440                 ret = - EINVAL;\r
441             }\r
442         }\r
443         break;\r
444         \r
445         default:\r
446             ;\r
447         break;\r
448     }\r
449     return ret;\r
450 }\r
451 \r
452 static unsigned int cmmbmemo_poll(struct file *file, struct poll_table_struct *wait)\r
453 {\r
454     struct cmmb_demux *cmmbmemo = (struct cmmb_memory*)file->private_data;\r
455     unsigned int mask = 0;\r
456 \r
457     DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
458     \r
459     //2todo memo poll, now doing nothing\r
460   \r
461     return mask;\r
462 }\r
463 \r
464 \r
465 static int cmmbmemo_mmap(struct file *file, struct vm_area_struct *vma)\r
466 {\r
467     //2 todo memo mmmap, now doing nothing\r
468     DBG("[CMMB HW]:[memory]:enter cmmbdemux_ioctl\n");\r
469     return 0;\r
470 }\r
471 \r
472 \r
473 struct file_operations cmmbmemeo_fops = \r
474 {\r
475     .open  = cmmbmemo_open,\r
476     .release = cmmbmemo_release,    \r
477     .read  = cmmbmemo_read,\r
478     .write = cmmbmemo_write,\r
479     .mmap  = cmmbmemo_mmap,\r
480     .poll  = cmmbmemo_poll,\r
481     .unlocked_ioctl = cmmbmemo_ioctl,\r
482 };\r
483 \r
484 static int __init cmmbmemo_init(void)\r
485 {\r
486     int res;\r
487     \r
488     DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
489         res =cmmb_register_device(&CMMB_adapter,&cmmbmemo, &cmmbmemeo_fops, NULL, CMMB_DEVICE_MEMO,"cmmb_memo");\r
490     mutex_init(&CMMB_memo.mutex);\r
491     CMMB_memo.usr = 0;\r
492     return res;\r
493 }\r
494 \r
495 static void __exit cmmbmemo_exit(void)\r
496 {\r
497     DBG("[CMMB HW]:[memory]:%s [%d]\n",__FUNCTION__,__LINE__);  \r
498     cmmb_unregister_device(cmmbmemo);\r
499     //mutex_destroy(mutex);\r
500 }\r
501 \r
502 module_init(cmmbmemo_init);\r
503 module_exit(cmmbmemo_exit);\r
504 \r
505 MODULE_DESCRIPTION("CMMB demodulator general driver");\r
506 MODULE_AUTHOR("HT,HZB,HH,LW");\r
507 MODULE_LICENSE("GPL");\r
508 \r