diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c b/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c index 5a995202289a..1811eb3096d3 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c @@ -433,6 +433,7 @@ static void vh264_notify_work(struct work_struct *work); static void user_data_push_work(struct work_struct *work); #ifdef MH264_USERDATA_ENABLE static void user_data_ready_notify_work(struct work_struct *work); +static void vmh264_wakeup_userdata_poll(void); #endif static const char vh264_dec_id[] = "vh264-dev"; @@ -5700,8 +5701,8 @@ static void print_data(unsigned char *pdata, rec_id, len, flag, duration, vpts, vpts_valid, poc_number); #endif - pr_info("%d len = %d, flag = %d, vpts = 0x%x, poc = %d\n", - rec_id, len, flag, vpts, poc); + pr_info("%d len = %d, flag = %d, vpts = 0x%x\n", + rec_id, len, flag, vpts); if (len == 96) { int i; @@ -6248,6 +6249,12 @@ static void vmh264_reset_userdata_fifo(struct vdec_s *vdec, int bInit) mutex_unlock(&hw->userdata_mutex); } } + +static void vmh264_wakeup_userdata_poll(void) +{ + amstream_wakeup_userdata_poll(); +} + #endif static void user_data_push_work(struct work_struct *work) @@ -7095,9 +7102,11 @@ static int ammvdec_h264_probe(struct platform_device *pdev) pdata->dump_state = vmh264_dump_state; #ifdef MH264_USERDATA_ENABLE + pdata->wakeup_userdata_poll = vmh264_wakeup_userdata_poll; pdata->user_data_read = vmh264_user_data_read; pdata->reset_userdata_fifo = vmh264_reset_userdata_fifo; #else + pdata->wakeup_userdata_poll = NULL; pdata->user_data_read = NULL; pdata->reset_userdata_fifo = NULL; #endif diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg12/vmpeg12.c b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg12/vmpeg12.c index 73d3f209e8a1..7dd1797bdf40 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg12/vmpeg12.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg12/vmpeg12.c @@ -1255,6 +1255,7 @@ static void vmpeg12_ppmgr_reset(void) #endif static void vmpeg12_reset_userdata_fifo(struct vdec_s *vdec, int bInit); +static void vmpeg12_wakeup_userdata_poll(void); static void reset_do_work(struct work_struct *work) { @@ -1669,6 +1670,11 @@ static void vmpeg12_reset_userdata_fifo(struct vdec_s *vdec, int bInit) mutex_unlock(&userdata_mutex); } +static void vmpeg12_wakeup_userdata_poll(void) +{ + amstream_wakeup_userdata_poll(); +} + static int vmpeg12_vdec_info_init(void) { gvs = kzalloc(sizeof(struct vdec_info), GFP_KERNEL); @@ -2016,7 +2022,7 @@ static int amvdec_mpeg12_probe(struct platform_device *pdev) pdata->user_data_read = vmpeg12_user_data_read; pdata->reset_userdata_fifo = vmpeg12_reset_userdata_fifo; - + pdata->wakeup_userdata_poll = vmpeg12_wakeup_userdata_poll; is_reset = 0; vmpeg12_vdec_info_init(); diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c b/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c index 635e856a7c93..6a6d32042cf7 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c @@ -3366,8 +3366,10 @@ EXPORT_SYMBOL(vdec_read_user_data); int vdec_wakeup_userdata_poll(struct vdec_s *vdec) { - /*if (vdec && vdec == vdec_get_default_vdec_for_userdata()) - amstream_wakeup_userdata_poll();*/ //DEBUG_TMP + if (vdec && vdec == vdec_get_default_vdec_for_userdata()) { + if (vdec->wakeup_userdata_poll) + vdec->wakeup_userdata_poll(); + } return 0; } diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.h b/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.h index a5db7617430e..219435a80400 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.h +++ b/drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.h @@ -234,7 +234,7 @@ struct vdec_s { int (*user_data_read)(struct vdec_s *vdec, struct userdata_param_t *puserdata_para); void (*reset_userdata_fifo)(struct vdec_s *vdec, int bInit); - + void (*wakeup_userdata_poll)(void); /* private */ void *private; /* decoder per instance specific data */ #ifdef VDEC_DEBUG_SUPPORT diff --git a/drivers/amlogic/media_modules/stream_input/Makefile b/drivers/amlogic/media_modules/stream_input/Makefile index fdc41621e46f..a10e6083b2a3 100644 --- a/drivers/amlogic/media_modules/stream_input/Makefile +++ b/drivers/amlogic/media_modules/stream_input/Makefile @@ -9,6 +9,7 @@ stream_input-objs += parser/esparser.o stream_input-objs += parser/tsdemux.o stream_input-objs += parser/psparser.o stream_input-objs += parser/rmparser.o +stream_input-objs += subtitle/subtitle.o obj-y += parser/hw_demux/ obj-y += tv_frontend/ diff --git a/drivers/amlogic/media_modules/stream_input/amports/amports_priv.h b/drivers/amlogic/media_modules/stream_input/amports/amports_priv.h index 53669a5951a9..c65368e295e8 100644 --- a/drivers/amlogic/media_modules/stream_input/amports/amports_priv.h +++ b/drivers/amlogic/media_modules/stream_input/amports/amports_priv.h @@ -44,6 +44,7 @@ int amstream_request_firmware_from_sys(const char *file_name, void set_vsync_pts_inc_mode(int inc); void set_real_audio_info(void *arg); +void amstream_wakeup_userdata_poll(void); #define dbg() pr_info("on %s,line %d\n", __func__, __LINE__); struct device *amports_get_dma_device(void); diff --git a/drivers/amlogic/media_modules/stream_input/amports/amstream.c b/drivers/amlogic/media_modules/stream_input/amports/amstream.c index 3bd37084837f..a05bbab3366d 100644 --- a/drivers/amlogic/media_modules/stream_input/amports/amstream.c +++ b/drivers/amlogic/media_modules/stream_input/amports/amstream.c @@ -80,6 +80,7 @@ #include "../../frame_provider/decoder/utils/firmware.h" #include "../../common/chips/chips.h" #include "../../common/chips/decoder_cpu_ver_info.h" +#include "../subtitle/subtitle.h" //#define G12A_BRINGUP_DEBUG @@ -1414,6 +1415,12 @@ int wakeup_userdata_poll(struct userdata_poc_info_t poc, return userdata_buf->buf_rp; } EXPORT_SYMBOL(wakeup_userdata_poll); +void amstream_wakeup_userdata_poll(void) +{ + atomic_set(&userdata_ready, 1); + wake_up_interruptible(&amstream_userdata_wait); +} +EXPORT_SYMBOL(amstream_wakeup_userdata_poll); static unsigned int amstream_userdata_poll(struct file *file, poll_table *wait_table) @@ -2994,9 +3001,22 @@ static long amstream_do_ioctl_old(struct port_priv_s *priv, } break; + case AMSTREAM_IOC_UD_BUF_READ: + { + struct userdata_param_t __user *p_userdata_param; + p_userdata_param = (void *)arg; + if (this->type & PORT_TYPE_USERDATA) { + if (vdec_read_user_data(NULL, + p_userdata_param) == 0) { + r = -EFAULT; + break; + } + } + } + break; case AMSTREAM_IOC_UD_FLUSH_USERDATA: if (this->type & PORT_TYPE_USERDATA) { - reset_userdata_fifo(0); + vdec_reset_userdata_fifo(NULL, 0); pr_info("reset_userdata_fifo\n"); } else r = -EINVAL; @@ -3900,12 +3920,19 @@ static int __init amstream_module_init(void) pr_err("failed to register amstream module\n"); return -ENODEV; } + + if (subtitle_init()) { + pr_err("failed to init subtitle\n"); + return -ENODEV; + } + return 0; } static void __exit amstream_module_exit(void) { platform_driver_unregister(&amstream_driver); + subtitle_exit(); } module_init(amstream_module_init); diff --git a/drivers/amlogic/media_modules/stream_input/subtitle/subtitle.c b/drivers/amlogic/media_modules/stream_input/subtitle/subtitle.c new file mode 100644 index 000000000000..5affce48b6ec --- /dev/null +++ b/drivers/amlogic/media_modules/stream_input/subtitle/subtitle.c @@ -0,0 +1,714 @@ +/* + * drivers/amlogic/media/subtitle/subtitle.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "amports_priv.h" + +//#include "amlog.h" +//MODULE_AMLOG(AMLOG_DEFAULT_LEVEL, 0, LOG_DEFAULT_LEVEL_DESC, + //LOG_DEFAULT_MASK_DESC); +#define DEVICE_NAME "amsubtitle" +/* Dev name as it appears in /proc/devices */ +#define DEVICE_CLASS_NAME "subtitle" + +static int subdevice_open; + +#define MAX_SUBTITLE_PACKET 10 +static DEFINE_MUTEX(amsubtitle_mutex); + +struct subtitle_data_s { + int subtitle_size; + int subtitle_pts; + char *data; +}; +static struct subtitle_data_s subtitle_data[MAX_SUBTITLE_PACKET]; +static int subtitle_enable = 1; +static int subtitle_total; +static int subtitle_width; +static int subtitle_height; +static int subtitle_type = -1; +static int subtitle_current; /* no subtitle */ +/* sub_index node will be modified by libplayer; amlogicplayer will use */ +/* it to detect wheather libplayer switch sub finished or not */ +static int subtitle_index; /* no subtitle */ +/* static int subtitle_size = 0; */ +/* static int subtitle_read_pos = 0; */ +static int subtitle_write_pos; +static int subtitle_start_pts; +static int subtitle_fps; +static int subtitle_subtype; +static int subtitle_reset; +/* static int *subltitle_address[MAX_SUBTITLE_PACKET]; */ + +enum subinfo_para_e { + SUB_NULL = -1, + SUB_ENABLE = 0, + SUB_TOTAL, + SUB_WIDTH, + SUB_HEIGHT, + SUB_TYPE, + SUB_CURRENT, + SUB_INDEX, + SUB_WRITE_POS, + SUB_START_PTS, + SUB_FPS, + SUB_SUBTYPE, + SUB_RESET, + SUB_DATA_T_SIZE, + SUB_DATA_T_DATA +}; + +struct subinfo_para_s { + enum subinfo_para_e subinfo_type; + int subtitle_info; + char *data; +}; + +/* total */ +/* curr */ +/* bimap */ +/* text */ +/* type */ +/* info */ +/* pts */ +/* duration */ +/* color pallete */ +/* width/height */ + +static ssize_t show_curr(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: current\n", subtitle_current); +} + +static ssize_t store_curr(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int curr; + ssize_t r; + + r = kstrtoint(buf, 0, &curr); + //r = sscanf(buf, "%d", &curr); + /* if ((r != 1)) */ + /* return -EINVAL; */ + + subtitle_current = curr; + + return size; +} + +static ssize_t show_index(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: current\n", subtitle_index); +} + +static ssize_t store_index(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int curr; + ssize_t r; + + r = kstrtoint(buf, 0, &curr); + /* if ((r != 1)) */ + /* return -EINVAL; */ + + subtitle_index = curr; + + return size; +} + +static ssize_t show_reset(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: current\n", subtitle_reset); +} + +static ssize_t store_reset(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int reset; + ssize_t r; + + r = kstrtoint(buf, 0, &reset); + + pr_info("reset is %d\n", reset); + /* if ((r != 1)) */ + /* return -EINVAL; */ + + subtitle_reset = reset; + + return size; +} + +static ssize_t show_type(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: type\n", subtitle_type); +} + +static ssize_t store_type(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int type; + ssize_t r; + + r = kstrtoint(buf, 0, &type); + /* if ((r != 1)) */ + /* return -EINVAL; */ + + subtitle_type = type; + + return size; +} + +static ssize_t show_width(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: width\n", subtitle_width); +} + +static ssize_t store_width(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int width; + ssize_t r; + + r = kstrtoint(buf, 0, &width); + /* if ((r != 1)) */ + /* return -EINVAL; */ + + subtitle_width = width; + + return size; +} + +static ssize_t show_height(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: height\n", subtitle_height); +} + +static ssize_t store_height(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int height; + ssize_t r; + + r = kstrtoint(buf, 0, &height); + /* if ((r != 1)) */ + /* return -EINVAL; */ + + subtitle_height = height; + + return size; +} + +static ssize_t show_total(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: num\n", subtitle_total); +} + +static ssize_t store_total(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int total; + ssize_t r; + + r = kstrtoint(buf, 0, &total); + if ((r <= 0)) + return -EINVAL; + pr_info("subtitle num is %d\n", total); + subtitle_total = total; + + return size; +} + +static ssize_t show_enable(struct class *class, struct class_attribute *attr, + char *buf) +{ + if (subtitle_enable) + return sprintf(buf, "1: enabled\n"); + + return sprintf(buf, "0: disabled\n"); +} + +static ssize_t store_enable(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int mode; + ssize_t r; + + r = kstrtoint(buf, 0, &mode); + if ((r != 1)) + return -EINVAL; + pr_info("subtitle enable is %d\n", mode); + subtitle_enable = mode ? 1 : 0; + + return size; +} + +static ssize_t show_size(struct class *class, struct class_attribute *attr, + char *buf) +{ + if (subtitle_enable) + return sprintf(buf, "1: size\n"); + + return sprintf(buf, "0: size\n"); +} + +static ssize_t store_size(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int ssize; + ssize_t r; + + r = kstrtoint(buf, 0, &ssize); + if ((r <= 0)) + return -EINVAL; + pr_info("subtitle size is %d\n", ssize); + subtitle_data[subtitle_write_pos].subtitle_size = ssize; + + return size; +} + +static ssize_t show_startpts(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: pts\n", subtitle_start_pts); +} + +static ssize_t store_startpts(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int spts; + ssize_t r; + + r = kstrtoint(buf, 0, &spts); + if ((r <= 0)) + return -EINVAL; + pr_info("subtitle start pts is %x\n", spts); + subtitle_start_pts = spts; + + return size; +} + +static ssize_t show_data(struct class *class, struct class_attribute *attr, + char *buf) +{ +#if 0 + if (subtitle_data[subtitle_write_pos].data) + return sprintf(buf, "%lld\n", + (unsigned long)(subtitle_data[subtitle_write_pos].data)); +#endif + return sprintf(buf, "0: disabled\n"); +} + +static ssize_t store_data(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int address; + ssize_t r; + + r = kstrtoint(buf, 0, &address); + if ((r == 0)) + return -EINVAL; +#if 0 + if (subtitle_data[subtitle_write_pos].subtitle_size > 0) { + subtitle_data[subtitle_write_pos].data = vmalloc(( + subtitle_data[subtitle_write_pos].subtitle_size)); + if (subtitle_data[subtitle_write_pos].data) + memcpy(subtitle_data[subtitle_write_pos].data, + (unsigned long *)address, + subtitle_data[subtitle_write_pos].subtitle_size); + } + pr_info("subtitle data address is %x", + (unsigned int)(subtitle_data[subtitle_write_pos].data)); +#endif + subtitle_write_pos++; + if (subtitle_write_pos >= MAX_SUBTITLE_PACKET) + subtitle_write_pos = 0; + return 1; +} + +static ssize_t show_fps(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: fps\n", subtitle_fps); +} + +static ssize_t store_fps(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int ssize; + ssize_t r; + + r = kstrtoint(buf, 0, &ssize); + if ((r <= 0)) + return -EINVAL; + pr_info("subtitle fps is %d\n", ssize); + subtitle_fps = ssize; + + return size; +} + +static ssize_t show_subtype(struct class *class, struct class_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d: subtype\n", subtitle_subtype); +} + +static ssize_t store_subtype(struct class *class, struct class_attribute *attr, + const char *buf, size_t size) +{ + unsigned int ssize; + ssize_t r; + + r = kstrtoint(buf, 0, &ssize); + if ((r <= 0)) + return -EINVAL; + pr_info("subtitle subtype is %d\n", ssize); + subtitle_subtype = ssize; + + return size; +} + +static struct class_attribute subtitle_class_attrs[] = { + __ATTR(enable, 0664, show_enable, store_enable), + __ATTR(total, 0664, show_total, store_total), + __ATTR(width, 0664, show_width, store_width), + __ATTR(height, 0664, show_height, store_height), + __ATTR(type, 0664, show_type, store_type), + __ATTR(curr, 0664, show_curr, store_curr), + __ATTR(index, 0664, show_index, store_index), + __ATTR(size, 0664, show_size, store_size), + __ATTR(data, 0664, show_data, store_data), + __ATTR(startpts, 0664, show_startpts, + store_startpts), + __ATTR(fps, 0664, show_fps, store_fps), + __ATTR(subtype, 0664, show_subtype, + store_subtype), + __ATTR(reset, 0644, show_reset, store_reset), + __ATTR_NULL +}; + + +/********************************************************* + * /dev/amvideo APIs + *********************************************************/ +static int amsubtitle_open(struct inode *inode, struct file *file) +{ + mutex_lock(&amsubtitle_mutex); + + if (subdevice_open) { + mutex_unlock(&amsubtitle_mutex); + return -EBUSY; + } + + subdevice_open = 1; + + try_module_get(THIS_MODULE); + + mutex_unlock(&amsubtitle_mutex); + + return 0; +} + +static int amsubtitle_release(struct inode *inode, struct file *file) +{ + mutex_lock(&amsubtitle_mutex); + + subdevice_open = 0; + + module_put(THIS_MODULE); + + mutex_unlock(&amsubtitle_mutex); + + return 0; +} + +static long amsubtitle_ioctl(struct file *file, unsigned int cmd, ulong arg) +{ + switch (cmd) { + case AMSTREAM_IOC_GET_SUBTITLE_INFO: { + struct subinfo_para_s Vstates; + struct subinfo_para_s *states = &Vstates; + + if (copy_from_user((void *)states, + (void *)arg, sizeof(Vstates))) + return -EFAULT; + switch (states->subinfo_type) { + case SUB_ENABLE: + states->subtitle_info = subtitle_enable; + break; + case SUB_TOTAL: + states->subtitle_info = subtitle_total; + break; + case SUB_WIDTH: + states->subtitle_info = subtitle_width; + break; + case SUB_HEIGHT: + states->subtitle_info = subtitle_height; + break; + case SUB_TYPE: + states->subtitle_info = subtitle_type; + break; + case SUB_CURRENT: + states->subtitle_info = subtitle_current; + break; + case SUB_INDEX: + states->subtitle_info = subtitle_index; + break; + case SUB_WRITE_POS: + states->subtitle_info = subtitle_write_pos; + break; + case SUB_START_PTS: + states->subtitle_info = subtitle_start_pts; + break; + case SUB_FPS: + states->subtitle_info = subtitle_fps; + break; + case SUB_SUBTYPE: + states->subtitle_info = subtitle_subtype; + break; + case SUB_RESET: + states->subtitle_info = subtitle_reset; + break; + case SUB_DATA_T_SIZE: + states->subtitle_info = + subtitle_data[subtitle_write_pos].subtitle_size; + break; + case SUB_DATA_T_DATA: { + if (states->subtitle_info > 0) + states->subtitle_info = + (long)subtitle_data[subtitle_write_pos].data; + } + break; + default: + break; + } + if (copy_to_user((void *)arg, (void *)states, sizeof(Vstates))) + return -EFAULT; + } + + break; + case AMSTREAM_IOC_SET_SUBTITLE_INFO: { + struct subinfo_para_s Vstates; + struct subinfo_para_s *states = &Vstates; + + if (copy_from_user((void *)states, + (void *)arg, sizeof(Vstates))) + return -EFAULT; + switch (states->subinfo_type) { + case SUB_ENABLE: + subtitle_enable = states->subtitle_info; + break; + case SUB_TOTAL: + subtitle_total = states->subtitle_info; + break; + case SUB_WIDTH: + subtitle_width = states->subtitle_info; + break; + case SUB_HEIGHT: + subtitle_height = states->subtitle_info; + break; + case SUB_TYPE: + subtitle_type = states->subtitle_info; + break; + case SUB_CURRENT: + subtitle_current = states->subtitle_info; + break; + case SUB_INDEX: + subtitle_index = states->subtitle_info; + break; + case SUB_WRITE_POS: + subtitle_write_pos = states->subtitle_info; + break; + case SUB_START_PTS: + subtitle_start_pts = states->subtitle_info; + break; + case SUB_FPS: + subtitle_fps = states->subtitle_info; + break; + case SUB_SUBTYPE: + subtitle_subtype = states->subtitle_info; + break; + case SUB_RESET: + subtitle_reset = states->subtitle_info; + break; + case SUB_DATA_T_SIZE: + subtitle_data[subtitle_write_pos].subtitle_size = + states->subtitle_info; + break; + case SUB_DATA_T_DATA: { + if (states->subtitle_info > 0) { + subtitle_data[subtitle_write_pos].data = + vmalloc((states->subtitle_info)); + if (subtitle_data[subtitle_write_pos].data) + memcpy( + subtitle_data[subtitle_write_pos].data, + (char *)states->data, + states->subtitle_info); + } + + subtitle_write_pos++; + if (subtitle_write_pos >= MAX_SUBTITLE_PACKET) + subtitle_write_pos = 0; + } + break; + default: + break; + } + + } + + break; + default: + break; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +static long amsub_compat_ioctl(struct file *file, unsigned int cmd, ulong arg) +{ + long ret = 0; + + ret = amsubtitle_ioctl(file, cmd, (ulong)compat_ptr(arg)); + return ret; +} +#endif + +static const struct file_operations amsubtitle_fops = { + .owner = THIS_MODULE, + .open = amsubtitle_open, + .release = amsubtitle_release, + .unlocked_ioctl = amsubtitle_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = amsub_compat_ioctl, +#endif +}; + +static struct device *amsubtitle_dev; +static dev_t amsub_devno; +static struct class *amsub_clsp; +static struct cdev *amsub_cdevp; +#define AMSUBTITLE_DEVICE_COUNT 1 + +static void create_amsub_attrs(struct class *class) +{ + int i = 0; + + for (i = 0; subtitle_class_attrs[i].attr.name; i++) { + if (class_create_file(class, &subtitle_class_attrs[i]) < 0) + break; + } +} + +static void remove_amsub_attrs(struct class *class) +{ + int i = 0; + + for (i = 0; subtitle_class_attrs[i].attr.name; i++) + class_remove_file(class, &subtitle_class_attrs[i]); +} + +int subtitle_init(void) +{ + int ret = 0; + + ret = alloc_chrdev_region(&amsub_devno, 0, AMSUBTITLE_DEVICE_COUNT, + DEVICE_NAME); + if (ret < 0) { + pr_info("amsub: failed to alloc major number\n"); + ret = -ENODEV; + return ret; + } + + amsub_clsp = class_create(THIS_MODULE, DEVICE_CLASS_NAME); + if (IS_ERR(amsub_clsp)) { + ret = PTR_ERR(amsub_clsp); + goto err1; + } + + create_amsub_attrs(amsub_clsp); + + amsub_cdevp = kmalloc(sizeof(struct cdev), GFP_KERNEL); + if (!amsub_cdevp) { + /*pr_info("amsub: failed to allocate memory\n");*/ + ret = -ENOMEM; + goto err2; + } + + cdev_init(amsub_cdevp, &amsubtitle_fops); + amsub_cdevp->owner = THIS_MODULE; + /* connect the major/minor number to cdev */ + ret = cdev_add(amsub_cdevp, amsub_devno, AMSUBTITLE_DEVICE_COUNT); + if (ret) { + pr_info("amsub:failed to add cdev\n"); + goto err3; + } + + amsubtitle_dev = device_create(amsub_clsp, + NULL, MKDEV(MAJOR(amsub_devno), 0), + NULL, DEVICE_NAME); + + if (IS_ERR(amsubtitle_dev)) { + pr_err("## Can't create amsubtitle device\n"); + goto err4; + } + + return 0; + +err4: + cdev_del(amsub_cdevp); +err3: + kfree(amsub_cdevp); +err2: + remove_amsub_attrs(amsub_clsp); + class_destroy(amsub_clsp); +err1: + unregister_chrdev_region(amsub_devno, 1); + + return ret; +} +EXPORT_SYMBOL(subtitle_init); + +void subtitle_exit(void) +{ + unregister_chrdev_region(amsub_devno, 1); + device_destroy(amsub_clsp, MKDEV(MAJOR(amsub_devno), 0)); + cdev_del(amsub_cdevp); + kfree(amsub_cdevp); + remove_amsub_attrs(amsub_clsp); + class_destroy(amsub_clsp); +} +EXPORT_SYMBOL(subtitle_exit); + diff --git a/drivers/amlogic/media_modules/stream_input/subtitle/subtitle.h b/drivers/amlogic/media_modules/stream_input/subtitle/subtitle.h new file mode 100644 index 000000000000..375a31a06d25 --- /dev/null +++ b/drivers/amlogic/media_modules/stream_input/subtitle/subtitle.h @@ -0,0 +1,24 @@ +/* + * drivers/amlogic/media/stream_input/amports/amports_priv.h + * + * Copyright (C) 2016 Amlogic, Inc. All rights reserved. + * + * 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. + * + */ + +#ifndef SUBTITLE_H +#define SUBTITLE_H + +int subtitle_init(void); +void subtitle_exit(void); + +#endif