mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 21:07:02 +09:00
media: Support Closed Caption and subtitle.
PD#170181 1.Add Support Closed Caption driver code. 2.Add subtitle driver code. Change-Id: If0c6023592c8a3f9fb50a301fe46c6dc3cadb2f1 Signed-off-by: Peng Yixin <yixin.peng@amlogic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
714
drivers/amlogic/media_modules/stream_input/subtitle/subtitle.c
Normal file
714
drivers/amlogic/media_modules/stream_input/subtitle/subtitle.c
Normal file
@@ -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 <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/amlogic/media/utils/amstream.h>
|
||||
#include <linux/uaccess.h>
|
||||
//#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);
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user