1 /*
2 * drivers/amlogic/media/subtitle/subtitle.c
3 *
4 * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17
18 #include <linux/module.h>
19 #include <linux/spinlock.h>
20 #include <linux/kernel.h>
21 #include <linux/device.h>
22 #include <linux/vmalloc.h>
23 #include <linux/major.h>
24 #include <linux/slab.h>
25 #include <linux/cdev.h>
26 #include <linux/fs.h>
27 #include <linux/interrupt.h>
28 #include <linux/amlogic/media/utils/amstream.h>
29 #include <linux/uaccess.h>
30 //#include "amports_priv.h"
31
32 //#include "amlog.h"
33 //MODULE_AMLOG(AMLOG_DEFAULT_LEVEL, 0, LOG_DEFAULT_LEVEL_DESC,
34 //LOG_DEFAULT_MASK_DESC);
35 #define DEVICE_NAME "amsubtitle"
36 /* Dev name as it appears in /proc/devices */
37 #define DEVICE_CLASS_NAME "subtitle"
38
39 static int subdevice_open;
40
41 #define MAX_SUBTITLE_PACKET 10
42 static DEFINE_MUTEX(amsubtitle_mutex);
43
44 struct subtitle_data_s {
45 int subtitle_size;
46 int subtitle_pts;
47 char *data;
48 };
49 static struct subtitle_data_s subtitle_data[MAX_SUBTITLE_PACKET];
50 static int subtitle_enable = 1;
51 static int subtitle_total;
52 static int subtitle_width;
53 static int subtitle_height;
54 static int subtitle_type = -1;
55 static int subtitle_current; /* no subtitle */
56 /* sub_index node will be modified by libplayer; amlogicplayer will use */
57 /* it to detect wheather libplayer switch sub finished or not */
58 static int subtitle_index; /* no subtitle */
59 /* static int subtitle_size = 0; */
60 /* static int subtitle_read_pos = 0; */
61 static int subtitle_write_pos;
62 static int subtitle_start_pts;
63 static int subtitle_fps;
64 static int subtitle_subtype;
65 static int subtitle_reset;
66 /* static int *subltitle_address[MAX_SUBTITLE_PACKET]; */
67
68 enum subinfo_para_e {
69 SUB_NULL = -1,
70 SUB_ENABLE = 0,
71 SUB_TOTAL,
72 SUB_WIDTH,
73 SUB_HEIGHT,
74 SUB_TYPE,
75 SUB_CURRENT,
76 SUB_INDEX,
77 SUB_WRITE_POS,
78 SUB_START_PTS,
79 SUB_FPS,
80 SUB_SUBTYPE,
81 SUB_RESET,
82 SUB_DATA_T_SIZE,
83 SUB_DATA_T_DATA
84 };
85
86 struct subinfo_para_s {
87 enum subinfo_para_e subinfo_type;
88 int subtitle_info;
89 char *data;
90 };
91
92 /* total */
93 /* curr */
94 /* bimap */
95 /* text */
96 /* type */
97 /* info */
98 /* pts */
99 /* duration */
100 /* color pallete */
101 /* width/height */
102
show_curr(struct class * class,struct class_attribute * attr,char * buf)103 static ssize_t show_curr(struct class *class, struct class_attribute *attr,
104 char *buf)
105 {
106 return sprintf(buf, "%d: current\n", subtitle_current);
107 }
108
store_curr(struct class * class,struct class_attribute * attr,const char * buf,size_t size)109 static ssize_t store_curr(struct class *class, struct class_attribute *attr,
110 const char *buf, size_t size)
111 {
112 unsigned int curr;
113 ssize_t r;
114
115 r = kstrtoint(buf, 0, &curr);
116 if (r < 0)
117 return -EINVAL;
118
119
120 subtitle_current = curr;
121
122 return size;
123 }
124
show_index(struct class * class,struct class_attribute * attr,char * buf)125 static ssize_t show_index(struct class *class, struct class_attribute *attr,
126 char *buf)
127 {
128 return sprintf(buf, "%d: current\n", subtitle_index);
129 }
130
store_index(struct class * class,struct class_attribute * attr,const char * buf,size_t size)131 static ssize_t store_index(struct class *class, struct class_attribute *attr,
132 const char *buf, size_t size)
133 {
134 unsigned int curr;
135 ssize_t r;
136
137 r = kstrtoint(buf, 0, &curr);
138 if (r < 0)
139 return -EINVAL;
140
141 subtitle_index = curr;
142
143 return size;
144 }
145
show_reset(struct class * class,struct class_attribute * attr,char * buf)146 static ssize_t show_reset(struct class *class, struct class_attribute *attr,
147 char *buf)
148 {
149 return sprintf(buf, "%d: current\n", subtitle_reset);
150 }
151
store_reset(struct class * class,struct class_attribute * attr,const char * buf,size_t size)152 static ssize_t store_reset(struct class *class, struct class_attribute *attr,
153 const char *buf, size_t size)
154 {
155 unsigned int reset;
156 ssize_t r;
157
158 r = kstrtoint(buf, 0, &reset);
159
160 pr_info("reset is %d\n", reset);
161 if (r < 0)
162 return -EINVAL;
163
164
165 subtitle_reset = reset;
166
167 return size;
168 }
169
show_type(struct class * class,struct class_attribute * attr,char * buf)170 static ssize_t show_type(struct class *class, struct class_attribute *attr,
171 char *buf)
172 {
173 return sprintf(buf, "%d: type\n", subtitle_type);
174 }
175
store_type(struct class * class,struct class_attribute * attr,const char * buf,size_t size)176 static ssize_t store_type(struct class *class, struct class_attribute *attr,
177 const char *buf, size_t size)
178 {
179 unsigned int type;
180 ssize_t r;
181
182 r = kstrtoint(buf, 0, &type);
183 if (r < 0)
184 return -EINVAL;
185
186 subtitle_type = type;
187
188 return size;
189 }
190
show_width(struct class * class,struct class_attribute * attr,char * buf)191 static ssize_t show_width(struct class *class, struct class_attribute *attr,
192 char *buf)
193 {
194 return sprintf(buf, "%d: width\n", subtitle_width);
195 }
196
store_width(struct class * class,struct class_attribute * attr,const char * buf,size_t size)197 static ssize_t store_width(struct class *class, struct class_attribute *attr,
198 const char *buf, size_t size)
199 {
200 unsigned int width;
201 ssize_t r;
202
203 r = kstrtoint(buf, 0, &width);
204 if (r < 0)
205 return -EINVAL;
206
207 subtitle_width = width;
208
209 return size;
210 }
211
show_height(struct class * class,struct class_attribute * attr,char * buf)212 static ssize_t show_height(struct class *class, struct class_attribute *attr,
213 char *buf)
214 {
215 return sprintf(buf, "%d: height\n", subtitle_height);
216 }
217
store_height(struct class * class,struct class_attribute * attr,const char * buf,size_t size)218 static ssize_t store_height(struct class *class, struct class_attribute *attr,
219 const char *buf, size_t size)
220 {
221 unsigned int height;
222 ssize_t r;
223
224 r = kstrtoint(buf, 0, &height);
225 if (r < 0)
226 return -EINVAL;
227
228 subtitle_height = height;
229
230 return size;
231 }
232
show_total(struct class * class,struct class_attribute * attr,char * buf)233 static ssize_t show_total(struct class *class, struct class_attribute *attr,
234 char *buf)
235 {
236 return sprintf(buf, "%d: num\n", subtitle_total);
237 }
238
store_total(struct class * class,struct class_attribute * attr,const char * buf,size_t size)239 static ssize_t store_total(struct class *class, struct class_attribute *attr,
240 const char *buf, size_t size)
241 {
242 unsigned int total;
243 ssize_t r;
244
245 r = kstrtoint(buf, 0, &total);
246 if (r < 0)
247 return -EINVAL;
248 pr_info("subtitle num is %d\n", total);
249 subtitle_total = total;
250
251 return size;
252 }
253
show_enable(struct class * class,struct class_attribute * attr,char * buf)254 static ssize_t show_enable(struct class *class, struct class_attribute *attr,
255 char *buf)
256 {
257 if (subtitle_enable)
258 return sprintf(buf, "1: enabled\n");
259
260 return sprintf(buf, "0: disabled\n");
261 }
262
store_enable(struct class * class,struct class_attribute * attr,const char * buf,size_t size)263 static ssize_t store_enable(struct class *class, struct class_attribute *attr,
264 const char *buf, size_t size)
265 {
266 unsigned int mode;
267 ssize_t r;
268
269 r = kstrtoint(buf, 0, &mode);
270 if (r < 0)
271 return -EINVAL;
272 pr_info("subtitle enable is %d\n", mode);
273 subtitle_enable = mode ? 1 : 0;
274
275 return size;
276 }
277
show_size(struct class * class,struct class_attribute * attr,char * buf)278 static ssize_t show_size(struct class *class, struct class_attribute *attr,
279 char *buf)
280 {
281 if (subtitle_enable)
282 return sprintf(buf, "1: size\n");
283
284 return sprintf(buf, "0: size\n");
285 }
286
store_size(struct class * class,struct class_attribute * attr,const char * buf,size_t size)287 static ssize_t store_size(struct class *class, struct class_attribute *attr,
288 const char *buf, size_t size)
289 {
290 unsigned int ssize;
291 ssize_t r;
292
293 r = kstrtoint(buf, 0, &ssize);
294 if (r < 0)
295 return -EINVAL;
296 pr_info("subtitle size is %d\n", ssize);
297 subtitle_data[subtitle_write_pos].subtitle_size = ssize;
298
299 return size;
300 }
301
show_startpts(struct class * class,struct class_attribute * attr,char * buf)302 static ssize_t show_startpts(struct class *class, struct class_attribute *attr,
303 char *buf)
304 {
305 return sprintf(buf, "%d: pts\n", subtitle_start_pts);
306 }
307
store_startpts(struct class * class,struct class_attribute * attr,const char * buf,size_t size)308 static ssize_t store_startpts(struct class *class, struct class_attribute *attr,
309 const char *buf, size_t size)
310 {
311 unsigned int spts;
312 ssize_t r;
313
314 r = kstrtoint(buf, 0, &spts);
315 if (r < 0)
316 return -EINVAL;
317 pr_info("subtitle start pts is %x\n", spts);
318 subtitle_start_pts = spts;
319
320 return size;
321 }
322
show_data(struct class * class,struct class_attribute * attr,char * buf)323 static ssize_t show_data(struct class *class, struct class_attribute *attr,
324 char *buf)
325 {
326 #if 0
327 if (subtitle_data[subtitle_write_pos].data)
328 return sprintf(buf, "%lld\n",
329 (unsigned long)(subtitle_data[subtitle_write_pos].data));
330 #endif
331 return sprintf(buf, "0: disabled\n");
332 }
333
store_data(struct class * class,struct class_attribute * attr,const char * buf,size_t size)334 static ssize_t store_data(struct class *class, struct class_attribute *attr,
335 const char *buf, size_t size)
336 {
337 unsigned int address;
338 ssize_t r;
339
340 r = kstrtoint(buf, 0, &address);
341 if ((r == 0))
342 return -EINVAL;
343 #if 0
344 if (subtitle_data[subtitle_write_pos].subtitle_size > 0) {
345 subtitle_data[subtitle_write_pos].data = vmalloc((
346 subtitle_data[subtitle_write_pos].subtitle_size));
347 if (subtitle_data[subtitle_write_pos].data)
348 memcpy(subtitle_data[subtitle_write_pos].data,
349 (unsigned long *)address,
350 subtitle_data[subtitle_write_pos].subtitle_size);
351 }
352 pr_info("subtitle data address is %x",
353 (unsigned int)(subtitle_data[subtitle_write_pos].data));
354 #endif
355 subtitle_write_pos++;
356 if (subtitle_write_pos >= MAX_SUBTITLE_PACKET)
357 subtitle_write_pos = 0;
358 return 1;
359 }
360
show_fps(struct class * class,struct class_attribute * attr,char * buf)361 static ssize_t show_fps(struct class *class, struct class_attribute *attr,
362 char *buf)
363 {
364 return sprintf(buf, "%d: fps\n", subtitle_fps);
365 }
366
store_fps(struct class * class,struct class_attribute * attr,const char * buf,size_t size)367 static ssize_t store_fps(struct class *class, struct class_attribute *attr,
368 const char *buf, size_t size)
369 {
370 unsigned int ssize;
371 ssize_t r;
372
373 r = kstrtoint(buf, 0, &ssize);
374 if (r < 0)
375 return -EINVAL;
376 pr_info("subtitle fps is %d\n", ssize);
377 subtitle_fps = ssize;
378
379 return size;
380 }
381
show_subtype(struct class * class,struct class_attribute * attr,char * buf)382 static ssize_t show_subtype(struct class *class, struct class_attribute *attr,
383 char *buf)
384 {
385 return sprintf(buf, "%d: subtype\n", subtitle_subtype);
386 }
387
store_subtype(struct class * class,struct class_attribute * attr,const char * buf,size_t size)388 static ssize_t store_subtype(struct class *class, struct class_attribute *attr,
389 const char *buf, size_t size)
390 {
391 unsigned int ssize;
392 ssize_t r;
393
394 r = kstrtoint(buf, 0, &ssize);
395 if (r < 0)
396 return -EINVAL;
397 pr_info("subtitle subtype is %d\n", ssize);
398 subtitle_subtype = ssize;
399
400 return size;
401 }
402
403 static struct class_attribute subtitle_class_attrs[] = {
404 __ATTR(enable, 0664, show_enable, store_enable),
405 __ATTR(total, 0664, show_total, store_total),
406 __ATTR(width, 0664, show_width, store_width),
407 __ATTR(height, 0664, show_height, store_height),
408 __ATTR(type, 0664, show_type, store_type),
409 __ATTR(curr, 0664, show_curr, store_curr),
410 __ATTR(index, 0664, show_index, store_index),
411 __ATTR(size, 0664, show_size, store_size),
412 __ATTR(data, 0664, show_data, store_data),
413 __ATTR(startpts, 0664, show_startpts,
414 store_startpts),
415 __ATTR(fps, 0664, show_fps, store_fps),
416 __ATTR(subtype, 0664, show_subtype,
417 store_subtype),
418 __ATTR(reset, 0644, show_reset, store_reset),
419 __ATTR_NULL
420 };
421
422
423 /*********************************************************
424 * /dev/amvideo APIs
425 *********************************************************/
amsubtitle_open(struct inode * inode,struct file * file)426 static int amsubtitle_open(struct inode *inode, struct file *file)
427 {
428 mutex_lock(&amsubtitle_mutex);
429
430 if (subdevice_open) {
431 mutex_unlock(&amsubtitle_mutex);
432 return -EBUSY;
433 }
434
435 subdevice_open = 1;
436
437 try_module_get(THIS_MODULE);
438
439 mutex_unlock(&amsubtitle_mutex);
440
441 return 0;
442 }
443
amsubtitle_release(struct inode * inode,struct file * file)444 static int amsubtitle_release(struct inode *inode, struct file *file)
445 {
446 mutex_lock(&amsubtitle_mutex);
447
448 subdevice_open = 0;
449
450 module_put(THIS_MODULE);
451
452 mutex_unlock(&amsubtitle_mutex);
453
454 return 0;
455 }
456
amsubtitle_ioctl(struct file * file,unsigned int cmd,ulong arg)457 static long amsubtitle_ioctl(struct file *file, unsigned int cmd, ulong arg)
458 {
459 switch (cmd) {
460 case AMSTREAM_IOC_GET_SUBTITLE_INFO: {
461 struct subinfo_para_s Vstates;
462 struct subinfo_para_s *states = &Vstates;
463
464 if (copy_from_user((void *)states,
465 (void *)arg, sizeof(Vstates)))
466 return -EFAULT;
467 switch (states->subinfo_type) {
468 case SUB_ENABLE:
469 states->subtitle_info = subtitle_enable;
470 break;
471 case SUB_TOTAL:
472 states->subtitle_info = subtitle_total;
473 break;
474 case SUB_WIDTH:
475 states->subtitle_info = subtitle_width;
476 break;
477 case SUB_HEIGHT:
478 states->subtitle_info = subtitle_height;
479 break;
480 case SUB_TYPE:
481 states->subtitle_info = subtitle_type;
482 break;
483 case SUB_CURRENT:
484 states->subtitle_info = subtitle_current;
485 break;
486 case SUB_INDEX:
487 states->subtitle_info = subtitle_index;
488 break;
489 case SUB_WRITE_POS:
490 states->subtitle_info = subtitle_write_pos;
491 break;
492 case SUB_START_PTS:
493 states->subtitle_info = subtitle_start_pts;
494 break;
495 case SUB_FPS:
496 states->subtitle_info = subtitle_fps;
497 break;
498 case SUB_SUBTYPE:
499 states->subtitle_info = subtitle_subtype;
500 break;
501 case SUB_RESET:
502 states->subtitle_info = subtitle_reset;
503 break;
504 case SUB_DATA_T_SIZE:
505 states->subtitle_info =
506 subtitle_data[subtitle_write_pos].subtitle_size;
507 break;
508 case SUB_DATA_T_DATA: {
509 if (states->subtitle_info > 0)
510 states->subtitle_info =
511 (long)subtitle_data[subtitle_write_pos].data;
512 }
513 break;
514 default:
515 break;
516 }
517 if (copy_to_user((void *)arg, (void *)states, sizeof(Vstates)))
518 return -EFAULT;
519 }
520
521 break;
522 case AMSTREAM_IOC_SET_SUBTITLE_INFO: {
523 struct subinfo_para_s Vstates;
524 struct subinfo_para_s *states = &Vstates;
525
526 if (copy_from_user((void *)states,
527 (void *)arg, sizeof(Vstates)))
528 return -EFAULT;
529 switch (states->subinfo_type) {
530 case SUB_ENABLE:
531 subtitle_enable = states->subtitle_info;
532 break;
533 case SUB_TOTAL:
534 subtitle_total = states->subtitle_info;
535 break;
536 case SUB_WIDTH:
537 subtitle_width = states->subtitle_info;
538 break;
539 case SUB_HEIGHT:
540 subtitle_height = states->subtitle_info;
541 break;
542 case SUB_TYPE:
543 subtitle_type = states->subtitle_info;
544 break;
545 case SUB_CURRENT:
546 subtitle_current = states->subtitle_info;
547 break;
548 case SUB_INDEX:
549 subtitle_index = states->subtitle_info;
550 break;
551 case SUB_WRITE_POS:
552 subtitle_write_pos = states->subtitle_info;
553 break;
554 case SUB_START_PTS:
555 subtitle_start_pts = states->subtitle_info;
556 break;
557 case SUB_FPS:
558 subtitle_fps = states->subtitle_info;
559 break;
560 case SUB_SUBTYPE:
561 subtitle_subtype = states->subtitle_info;
562 break;
563 case SUB_RESET:
564 subtitle_reset = states->subtitle_info;
565 break;
566 case SUB_DATA_T_SIZE:
567 subtitle_data[subtitle_write_pos].subtitle_size =
568 states->subtitle_info;
569 break;
570 case SUB_DATA_T_DATA: {
571 if (states->subtitle_info > 0) {
572 subtitle_data[subtitle_write_pos].data =
573 vmalloc((states->subtitle_info));
574 if (subtitle_data[subtitle_write_pos].data)
575 memcpy(
576 subtitle_data[subtitle_write_pos].data,
577 (char *)states->data,
578 states->subtitle_info);
579 }
580
581 subtitle_write_pos++;
582 if (subtitle_write_pos >= MAX_SUBTITLE_PACKET)
583 subtitle_write_pos = 0;
584 }
585 break;
586 default:
587 break;
588 }
589
590 }
591
592 break;
593 default:
594 break;
595 }
596
597 return 0;
598 }
599
600 #ifdef CONFIG_COMPAT
amsub_compat_ioctl(struct file * file,unsigned int cmd,ulong arg)601 static long amsub_compat_ioctl(struct file *file, unsigned int cmd, ulong arg)
602 {
603 long ret = 0;
604
605 ret = amsubtitle_ioctl(file, cmd, (ulong)compat_ptr(arg));
606 return ret;
607 }
608 #endif
609
610 static const struct file_operations amsubtitle_fops = {
611 .owner = THIS_MODULE,
612 .open = amsubtitle_open,
613 .release = amsubtitle_release,
614 .unlocked_ioctl = amsubtitle_ioctl,
615 #ifdef CONFIG_COMPAT
616 .compat_ioctl = amsub_compat_ioctl,
617 #endif
618 };
619
620 static struct device *amsubtitle_dev;
621 static dev_t amsub_devno;
622 static struct class *amsub_clsp;
623 static struct cdev *amsub_cdevp;
624 #define AMSUBTITLE_DEVICE_COUNT 1
625
create_amsub_attrs(struct class * class)626 static void create_amsub_attrs(struct class *class)
627 {
628 int i = 0;
629
630 for (i = 0; subtitle_class_attrs[i].attr.name; i++) {
631 if (class_create_file(class, &subtitle_class_attrs[i]) < 0)
632 break;
633 }
634 }
635
remove_amsub_attrs(struct class * class)636 static void remove_amsub_attrs(struct class *class)
637 {
638 int i = 0;
639
640 for (i = 0; subtitle_class_attrs[i].attr.name; i++)
641 class_remove_file(class, &subtitle_class_attrs[i]);
642 }
643
subtitle_init(void)644 int subtitle_init(void)
645 {
646 int ret = 0;
647
648 ret = alloc_chrdev_region(&amsub_devno, 0, AMSUBTITLE_DEVICE_COUNT,
649 DEVICE_NAME);
650 if (ret < 0) {
651 pr_info("amsub: failed to alloc major number\n");
652 ret = -ENODEV;
653 return ret;
654 }
655
656 amsub_clsp = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
657 if (IS_ERR(amsub_clsp)) {
658 ret = PTR_ERR(amsub_clsp);
659 goto err1;
660 }
661
662 create_amsub_attrs(amsub_clsp);
663
664 amsub_cdevp = kmalloc(sizeof(struct cdev), GFP_KERNEL);
665 if (!amsub_cdevp) {
666 /*pr_info("amsub: failed to allocate memory\n");*/
667 ret = -ENOMEM;
668 goto err2;
669 }
670
671 cdev_init(amsub_cdevp, &amsubtitle_fops);
672 amsub_cdevp->owner = THIS_MODULE;
673 /* connect the major/minor number to cdev */
674 ret = cdev_add(amsub_cdevp, amsub_devno, AMSUBTITLE_DEVICE_COUNT);
675 if (ret) {
676 pr_info("amsub:failed to add cdev\n");
677 goto err3;
678 }
679
680 amsubtitle_dev = device_create(amsub_clsp,
681 NULL, MKDEV(MAJOR(amsub_devno), 0),
682 NULL, DEVICE_NAME);
683
684 if (IS_ERR(amsubtitle_dev)) {
685 pr_err("## Can't create amsubtitle device\n");
686 goto err4;
687 }
688
689 return 0;
690
691 err4:
692 cdev_del(amsub_cdevp);
693 err3:
694 kfree(amsub_cdevp);
695 err2:
696 remove_amsub_attrs(amsub_clsp);
697 class_destroy(amsub_clsp);
698 err1:
699 unregister_chrdev_region(amsub_devno, 1);
700
701 return ret;
702 }
703 EXPORT_SYMBOL(subtitle_init);
704
subtitle_exit(void)705 void subtitle_exit(void)
706 {
707 unregister_chrdev_region(amsub_devno, 1);
708 device_destroy(amsub_clsp, MKDEV(MAJOR(amsub_devno), 0));
709 cdev_del(amsub_cdevp);
710 kfree(amsub_cdevp);
711 remove_amsub_attrs(amsub_clsp);
712 class_destroy(amsub_clsp);
713 }
714 EXPORT_SYMBOL(subtitle_exit);
715
716