187 lines
5.1 KiB
C
Executable file
187 lines
5.1 KiB
C
Executable file
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/* sound/soc/samsung/vts/vts_dump.c
|
|
*
|
|
* ALSA SoC - Samsung VTS dump driver
|
|
*
|
|
* Copyright (c) 2017 Samsung Electronics Co. Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
//#define DEBUG
|
|
#include <linux/module.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <sound/soc.h>
|
|
|
|
#include "vts_dump.h"
|
|
#include "vts_dbg.h"
|
|
|
|
#define S_IRWUG (0660)
|
|
|
|
struct vts_dump_info {
|
|
struct device *dev;
|
|
struct mutex audiolock;
|
|
struct mutex loglock;
|
|
u32 audioaddr_offset;
|
|
u32 audiodump_sz;
|
|
u32 logaddr_offset;
|
|
u32 logdump_sz;
|
|
};
|
|
|
|
static struct vts_dump_info gdump_info;
|
|
|
|
static void vts_audiodump_flush_work_func(struct work_struct *work)
|
|
{
|
|
struct device *dev = gdump_info.dev;
|
|
struct vts_dump_info *dump_info = &gdump_info;
|
|
struct vts_data *data = dev_get_drvdata(dev);
|
|
char filename[SZ_64];
|
|
/* struct file *filp; */
|
|
|
|
vts_dev_dbg(dev, "%s: SRAM Offset: 0x%x Size: %d\n", __func__,
|
|
dump_info->audioaddr_offset, dump_info->audiodump_sz);
|
|
|
|
mutex_lock(&gdump_info.audiolock);
|
|
sprintf(filename, "/data/vts_audiodump.raw");
|
|
|
|
/* filp = filp_open(filename, O_RDWR | O_APPEND | O_CREAT, S_IRWUG);
|
|
* vts_dev_info(dev, "AudioDump appended mode\n");
|
|
* if (!IS_ERR_OR_NULL(filp)) {
|
|
* void *area = (void *)(data->sram_base + dump_info->audioaddr_offset);
|
|
* size_t bytes = (size_t)dump_info->audiodump_sz;
|
|
* vts_dev_dbg(dev, " %p, %zx\n", area, bytes);
|
|
* kernel_write(filp, area, bytes, &filp->f_pos);
|
|
* dev_dbg(dev, "kernel_write %p, %zx\n", area, bytes);
|
|
* vfs_fsync(filp, 1);
|
|
* filp_close(filp, NULL);
|
|
* } else {
|
|
* vts_dev_err(dev, "VTS Audiodump file [%s] open
|
|
* error: %ld\n", filename, PTR_ERR(filp));
|
|
* }
|
|
*/
|
|
|
|
vts_send_ipc_ack(data, 1);
|
|
mutex_unlock(&gdump_info.audiolock);
|
|
}
|
|
|
|
static void vts_logdump_flush_work_func(struct work_struct *work)
|
|
{
|
|
struct device *dev = gdump_info.dev;
|
|
struct vts_dump_info *dump_info = &gdump_info;
|
|
struct vts_data *data = dev_get_drvdata(dev);
|
|
char filename[SZ_64];
|
|
/* struct file *filp; */
|
|
|
|
vts_dev_dbg(dev, "%s: SRAM Offset: 0x%x Size: %d\n", __func__,
|
|
dump_info->logaddr_offset, dump_info->logdump_sz);
|
|
|
|
mutex_lock(&gdump_info.loglock);
|
|
sprintf(filename, "/data/vts_logdump.txt");
|
|
|
|
/* filp = filp_open(filename, O_RDWR | O_APPEND | O_CREAT, S_IRWUG);
|
|
* vts_dev_info(dev, "LogDump appended mode\n");
|
|
* if (!IS_ERR_OR_NULL(filp)) {
|
|
* void *area = (void *)(data->sram_base + dump_info->logaddr_offset);
|
|
* size_t bytes = (size_t)dump_info->logdump_sz;
|
|
* vts_dev_dbg(dev, " %p, %zx\n", area, bytes);
|
|
* kernel_write(filp, area, bytes, &filp->f_pos);
|
|
* dev_dbg(dev, "kernel_write %p, %zx\n", area, bytes);
|
|
* vfs_fsync(filp, 1);
|
|
* filp_close(filp, NULL);
|
|
* } else {
|
|
* vts_dev_err(dev, "VTS Logdump file [%s] open error: %ld\n",
|
|
* filename, PTR_ERR(filp));
|
|
* }
|
|
*/
|
|
|
|
vts_send_ipc_ack(data, 1);
|
|
mutex_unlock(&gdump_info.loglock);
|
|
}
|
|
|
|
static DECLARE_WORK(vts_audiodump_work, vts_audiodump_flush_work_func);
|
|
static DECLARE_WORK(vts_logdump_work, vts_logdump_flush_work_func);
|
|
void vts_audiodump_schedule_flush(struct device *dev)
|
|
{
|
|
struct vts_data *data = dev_get_drvdata(dev);
|
|
|
|
if (gdump_info.audioaddr_offset) {
|
|
schedule_work(&vts_audiodump_work);
|
|
vts_dev_dbg(dev, "%s: AudioDump Scheduled\n", __func__);
|
|
} else {
|
|
vts_dev_warn(dev, "%s: AudioDump address not registered\n",
|
|
__func__);
|
|
/* send ipc ack to unblock vts firmware */
|
|
vts_send_ipc_ack(data, 1);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(vts_audiodump_schedule_flush);
|
|
|
|
void vts_logdump_schedule_flush(struct device *dev)
|
|
{
|
|
struct vts_data *data = dev_get_drvdata(dev);
|
|
|
|
if (gdump_info.logaddr_offset) {
|
|
schedule_work(&vts_logdump_work);
|
|
vts_dev_dbg(dev, "%s: LogDump Scheduled\n", __func__);
|
|
} else {
|
|
vts_dev_warn(dev, "%s: LogDump address not registered\n",
|
|
__func__);
|
|
/* send ipc ack to unblock vts firmware */
|
|
vts_send_ipc_ack(data, 1);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(vts_logdump_schedule_flush);
|
|
|
|
static int samsung_vts_dump_initcall(void)
|
|
{
|
|
static int has_run;
|
|
|
|
if (has_run)
|
|
return 0;
|
|
|
|
has_run = 1;
|
|
pr_info("%s\n", __func__);
|
|
mutex_init(&gdump_info.audiolock);
|
|
mutex_init(&gdump_info.loglock);
|
|
gdump_info.audioaddr_offset = 0;
|
|
gdump_info.audiodump_sz = 0;
|
|
gdump_info.logaddr_offset = 0;
|
|
gdump_info.logdump_sz = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void vts_dump_addr_register(
|
|
struct device *dev,
|
|
u32 addroffset,
|
|
u32 dumpsz,
|
|
u32 dump_mode)
|
|
{
|
|
struct vts_data *data = dev_get_drvdata(dev);
|
|
|
|
samsung_vts_dump_initcall();
|
|
|
|
gdump_info.dev = dev;
|
|
if ((addroffset + dumpsz) > data->sram_size) {
|
|
vts_dev_warn(dev, "%s: wrong offset[0x%x] or size[0x%x]\n",
|
|
__func__, addroffset, dumpsz);
|
|
return;
|
|
}
|
|
|
|
if (dump_mode == VTS_AUDIO_DUMP) {
|
|
gdump_info.audioaddr_offset = addroffset;
|
|
gdump_info.audiodump_sz = dumpsz;
|
|
} else if (dump_mode == VTS_LOG_DUMP) {
|
|
gdump_info.logaddr_offset = addroffset;
|
|
gdump_info.logdump_sz = dumpsz;
|
|
} else
|
|
vts_dev_warn(dev, "%s: Unknown dump mode\n", __func__);
|
|
|
|
vts_dev_info(dev, "%s: %sDump offset[0x%x] size [%d]Scheduled\n",
|
|
__func__, (dump_mode ? "Log" : "Audio"),
|
|
addroffset, dumpsz);
|
|
}
|
|
EXPORT_SYMBOL(vts_dump_addr_register);
|