mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-10 09:22:44 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
304
drivers/misc/samsung/scsc/mxlog.c
Normal file
304
drivers/misc/samsung/scsc/mxlog.c
Normal file
|
@ -0,0 +1,304 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <scsc/scsc_logring.h>
|
||||
#include <scsc/scsc_mx.h>
|
||||
#include "scsc_mx_impl.h"
|
||||
#include "mxmgmt_transport.h"
|
||||
#include "mxlog_transport.h"
|
||||
#include "mxlog.h"
|
||||
|
||||
/*
|
||||
* Receive handler for messages from the FW along the maxwell management transport
|
||||
*/
|
||||
static inline void mxlog_phase4_message_handler(const void *message,
|
||||
size_t length, u32 level,
|
||||
void *data)
|
||||
{
|
||||
unsigned char *buf = (unsigned char *)message;
|
||||
|
||||
SCSC_TAG_LVL(MX_FW, level, "%d: %s\n", (int)length, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to parse a NULL terminated format string
|
||||
* and report on the provided output bitmaps smap/lmap which args
|
||||
* are 'long' and which are signedi...as in %ld.
|
||||
*/
|
||||
static inline void build_len_sign_maps(char *fmt, u32 *smap, u32 *lmap)
|
||||
{
|
||||
u32 p = 0;
|
||||
char *s = fmt;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
for (; *s != '\0'; ++s) {
|
||||
if (*s != '%')
|
||||
continue;
|
||||
if (*++s == 'l') {
|
||||
*lmap |= (1 << p);
|
||||
++s;
|
||||
}
|
||||
if (*s == 'd')
|
||||
*smap |= (1 << p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The binary protocol described at:
|
||||
*
|
||||
* http://wiki/Maxwell_common_firmware/Mxlog#Phase_5_:_string_decoded_on_the_host
|
||||
*
|
||||
* states that we'd receive the following record content on each mxlog
|
||||
* message from FW, where:
|
||||
*
|
||||
* - each element is a 32bit word
|
||||
* - 1st element is a record header
|
||||
* - len = number of elements following the first element
|
||||
*
|
||||
* | 1st | 2nd | 3rd | 4th | 5th | 6th
|
||||
* -----------------------------------------------------------
|
||||
* | sync|lvl|len || tstamp || offset || arg1 || arg2 || arg3.
|
||||
* -----------------------------------------------------------
|
||||
* | e l o g m s g |
|
||||
*
|
||||
* BUT NOTE THAT: here we DO NOT receive 1st header element BUT
|
||||
* instead we got:
|
||||
* @message: pointer to 2nd element
|
||||
* @length: in bytes of the message (so starting from 2nd element) and
|
||||
* including tstamp and offset elements: we must calculate
|
||||
* num_args accordingly.
|
||||
* @level: the debug level already remapped from FW to Kernel namespace
|
||||
*/
|
||||
static inline void mxlog_phase5_message_handler(const void *message,
|
||||
size_t length, u32 level,
|
||||
void *data)
|
||||
{
|
||||
struct mxlog *mxlog = (struct mxlog *)data;
|
||||
struct mxlog_event_log_msg *elogmsg =
|
||||
(struct mxlog_event_log_msg *)message;
|
||||
|
||||
if (length < MINIMUM_MXLOG_MSG_LEN_BYTES)
|
||||
return;
|
||||
if (mxlog && elogmsg) {
|
||||
int num_args = 0;
|
||||
char spare[MAX_SPARE_FMT + TSTAMP_LEN] = {};
|
||||
char *fmt = NULL;
|
||||
size_t fmt_sz = 0;
|
||||
u32 smap = 0, lmap = 0;
|
||||
u32 *args = NULL;
|
||||
|
||||
/* Check OFFSET sanity... beware of FW guys :D ! */
|
||||
if (elogmsg->offset >= mxlog->logstrings->size) {
|
||||
SCSC_TAG_ERR(MX_FW,
|
||||
"Received message OFFSET(%d) is OUT OF range(%zd)...skip..\n",
|
||||
elogmsg->offset, mxlog->logstrings->size);
|
||||
return;
|
||||
}
|
||||
args = (u32 *)(elogmsg + 1);
|
||||
num_args =
|
||||
(length - MINIMUM_MXLOG_MSG_LEN_BYTES) /
|
||||
MXLOG_ELEMENT_SIZE;
|
||||
fmt = (char *)(mxlog->logstrings->data + elogmsg->offset);
|
||||
/* Avoid being fooled by a NON NULL-terminated strings too ! */
|
||||
fmt_sz = strnlen(fmt,
|
||||
mxlog->logstrings->size - elogmsg->offset);
|
||||
if (fmt_sz >= MAX_SPARE_FMT - 1) {
|
||||
SCSC_TAG_ERR(MX_FW,
|
||||
"UNSUPPORTED message length %zd ... truncated.\n",
|
||||
fmt_sz);
|
||||
fmt_sz = MAX_SPARE_FMT - 2;
|
||||
}
|
||||
/* Pre-Process fmt string to be able to do proper casting */
|
||||
if (num_args)
|
||||
build_len_sign_maps(fmt, &smap, &lmap);
|
||||
/* Add FW provided tstamp on front and proper \n at
|
||||
* the end when needed
|
||||
*/
|
||||
snprintf(spare, MAX_SPARE_FMT + TSTAMP_LEN - 2, "%08X %s%c",
|
||||
elogmsg->timestamp, fmt,
|
||||
(fmt[fmt_sz] != '\n') ? '\n' : '\0');
|
||||
fmt = spare;
|
||||
|
||||
switch (num_args) {
|
||||
case 0:
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt);
|
||||
break;
|
||||
case 1:
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt,
|
||||
MXLOG_CAST(args[0], 0, smap, lmap));
|
||||
break;
|
||||
case 2:
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt,
|
||||
MXLOG_CAST(args[0], 0, smap, lmap),
|
||||
MXLOG_CAST(args[1], 1, smap, lmap));
|
||||
break;
|
||||
case 3:
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt,
|
||||
MXLOG_CAST(args[0], 0, smap, lmap),
|
||||
MXLOG_CAST(args[1], 1, smap, lmap),
|
||||
MXLOG_CAST(args[2], 2, smap, lmap));
|
||||
break;
|
||||
case 4:
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt,
|
||||
MXLOG_CAST(args[0], 0, smap, lmap),
|
||||
MXLOG_CAST(args[1], 1, smap, lmap),
|
||||
MXLOG_CAST(args[2], 2, smap, lmap),
|
||||
MXLOG_CAST(args[3], 3, smap, lmap));
|
||||
break;
|
||||
case 5:
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt,
|
||||
MXLOG_CAST(args[0], 0, smap, lmap),
|
||||
MXLOG_CAST(args[1], 1, smap, lmap),
|
||||
MXLOG_CAST(args[2], 2, smap, lmap),
|
||||
MXLOG_CAST(args[3], 3, smap, lmap),
|
||||
MXLOG_CAST(args[4], 4, smap, lmap));
|
||||
break;
|
||||
case 6:
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt,
|
||||
MXLOG_CAST(args[0], 0, smap, lmap),
|
||||
MXLOG_CAST(args[1], 1, smap, lmap),
|
||||
MXLOG_CAST(args[2], 2, smap, lmap),
|
||||
MXLOG_CAST(args[3], 3, smap, lmap),
|
||||
MXLOG_CAST(args[4], 4, smap, lmap),
|
||||
MXLOG_CAST(args[5], 5, smap, lmap));
|
||||
break;
|
||||
case 7:
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt,
|
||||
MXLOG_CAST(args[0], 0, smap, lmap),
|
||||
MXLOG_CAST(args[1], 1, smap, lmap),
|
||||
MXLOG_CAST(args[2], 2, smap, lmap),
|
||||
MXLOG_CAST(args[3], 3, smap, lmap),
|
||||
MXLOG_CAST(args[4], 4, smap, lmap),
|
||||
MXLOG_CAST(args[5], 5, smap, lmap),
|
||||
MXLOG_CAST(args[6], 6, smap, lmap));
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
if (num_args > MAX_MX_LOG_ARGS)
|
||||
SCSC_TAG_ERR(MX_FW,
|
||||
"MXLOG: Too many args:%d ... print only first %d\n",
|
||||
num_args, MAX_MX_LOG_ARGS);
|
||||
SCSC_TAG_LVL(MX_FW, level, fmt,
|
||||
MXLOG_CAST(args[0], 0, smap, lmap),
|
||||
MXLOG_CAST(args[1], 1, smap, lmap),
|
||||
MXLOG_CAST(args[2], 2, smap, lmap),
|
||||
MXLOG_CAST(args[3], 3, smap, lmap),
|
||||
MXLOG_CAST(args[4], 4, smap, lmap),
|
||||
MXLOG_CAST(args[5], 5, smap, lmap),
|
||||
MXLOG_CAST(args[6], 6, smap, lmap),
|
||||
MXLOG_CAST(args[7], 7, smap, lmap));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* A generic message handler to multiplex between phases */
|
||||
static void mxlog_message_handler(u8 phase, const void *message,
|
||||
size_t length, u32 level, void *data)
|
||||
{
|
||||
struct mxlog *mxlog = (struct mxlog *)data;
|
||||
|
||||
if (!mxlog) {
|
||||
SCSC_TAG_ERR(MX_FW, "Missing MXLOG reference.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (phase) {
|
||||
case MX_LOG_PHASE_4:
|
||||
mxlog_phase4_message_handler(message, length, level, data);
|
||||
break;
|
||||
case MX_LOG_PHASE_5:
|
||||
if (mxlog->logstrings)
|
||||
mxlog_phase5_message_handler(message, length,
|
||||
level, data);
|
||||
else
|
||||
SCSC_TAG_ERR(MX_FW,
|
||||
"Missing LogStrings...dropping incoming PHASE5 message !\n");
|
||||
break;
|
||||
default:
|
||||
SCSC_TAG_ERR(MX_FW,
|
||||
"MXLOG Unsupported phase %d ... dropping message !\n",
|
||||
phase);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int mxlog_header_parser(u32 header, u8 *phase,
|
||||
u8 *level, u32 *num_bytes)
|
||||
{
|
||||
u32 fw2kern_map[] = {
|
||||
0, /* 0 MX_ERROR --> 0 KERN_EMERG .. it's panic.*/
|
||||
4, /* 1 MX_WARN --> 4 KERN_WARNING */
|
||||
5, /* 2 MX_MAJOR --> 5 KERN_NOTICE */
|
||||
6, /* 3 MX_MINOR --> 6 KERN_INFO */
|
||||
7, /* 4 MX_DETAIL --> 7 KERN_DEBUG */
|
||||
};
|
||||
u16 sync = ((header & 0xFFFF0000) >> 16);
|
||||
|
||||
switch (sync) {
|
||||
case SYNC_VALUE_PHASE_4:
|
||||
*phase = MX_LOG_PHASE_4;
|
||||
/* len() field represent number of chars bytes */
|
||||
*num_bytes = header & 0x000000FF;
|
||||
break;
|
||||
case SYNC_VALUE_PHASE_5:
|
||||
*phase = MX_LOG_PHASE_5;
|
||||
/* len() field represent number of 4 bytes words */
|
||||
*num_bytes = (header & 0x000000FF) * 4;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
/* Remap FW debug levels to KERN debug levels domain */
|
||||
*level = (header & 0x0000FF00) >> 8;
|
||||
if (*level < ARRAY_SIZE(fw2kern_map)) {
|
||||
*level = fw2kern_map[*level];
|
||||
} else {
|
||||
SCSC_TAG_ERR(MX_FW,
|
||||
"UNKNOWN MX debug level %d ... marking as MX_DETAIL.\n",
|
||||
*level);
|
||||
*level = fw2kern_map[ARRAY_SIZE(fw2kern_map) - 1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mxlog_init(struct mxlog *mxlog, struct scsc_mx *mx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mxlog->mx = mx;
|
||||
mxlog->index = 0;
|
||||
mxlog->logstrings = NULL;
|
||||
|
||||
/* File is in f/w profile directory */
|
||||
ret = mx140_file_request_debug_conf(mx,
|
||||
(const struct firmware **)&mxlog->logstrings,
|
||||
MX_LOG_LOGSTRINGS_PATH);
|
||||
|
||||
if (!ret && mxlog->logstrings)
|
||||
SCSC_TAG_INFO(MX_FW, "Loaded %zd bytes of log-strings from %s\n",
|
||||
mxlog->logstrings->size, MX_LOG_LOGSTRINGS_PATH);
|
||||
else
|
||||
SCSC_TAG_ERR(MX_FW, "Failed to read %s needed by MXlog Phase 5\n",
|
||||
MX_LOG_LOGSTRINGS_PATH);
|
||||
/* Registering a generic channel handler */
|
||||
mxlog_transport_register_channel_handler(scsc_mx_get_mxlog_transport(mx),
|
||||
&mxlog_header_parser,
|
||||
&mxlog_message_handler, mxlog);
|
||||
}
|
||||
|
||||
void mxlog_release(struct mxlog *mxlog)
|
||||
{
|
||||
mxlog_transport_register_channel_handler(scsc_mx_get_mxlog_transport(mxlog->mx),
|
||||
NULL, NULL, NULL);
|
||||
if (mxlog->logstrings)
|
||||
mx140_release_file(mxlog->mx, mxlog->logstrings);
|
||||
mxlog->logstrings = NULL;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue