diag: Add support for multi connection logging

This change adds support to route On-Device logging and
USB logging traffic per peripheral. A peripherals'
traffic can go to either endpoint but not both. The
mux layer has a peripheral state and the mode switching
logic has multi mode support.

CRs-Fixed: 1004236
Change-Id: I54fef744bdf08a346e4aef22c1280e928cdaf5d2
Signed-off-by: Chris Lew <clew@codeaurora.org>
This commit is contained in:
Chris Lew 2016-04-20 08:34:16 -07:00 committed by Kyle Yan
parent 0db49c2550
commit b1e748622f
5 changed files with 314 additions and 190 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -23,11 +23,13 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include "diagchar.h" #include "diagchar.h"
#include "diagfwd.h"
#include "diag_mux.h" #include "diag_mux.h"
#include "diag_usb.h" #include "diag_usb.h"
#include "diag_memorydevice.h" #include "diag_memorydevice.h"
struct diag_logger_t *logger;
struct diag_mux_state_t *diag_mux;
static struct diag_logger_t usb_logger; static struct diag_logger_t usb_logger;
static struct diag_logger_t md_logger; static struct diag_logger_t md_logger;
@ -49,11 +51,11 @@ static struct diag_logger_ops md_log_ops = {
int diag_mux_init() int diag_mux_init()
{ {
logger = kzalloc(NUM_MUX_PROC * sizeof(struct diag_logger_t), diag_mux = kzalloc(sizeof(struct diag_mux_state_t),
GFP_KERNEL); GFP_KERNEL);
if (!logger) if (!diag_mux)
return -ENOMEM; return -ENOMEM;
kmemleak_not_leak(logger); kmemleak_not_leak(diag_mux);
usb_logger.mode = DIAG_USB_MODE; usb_logger.mode = DIAG_USB_MODE;
usb_logger.log_ops = &usb_log_ops; usb_logger.log_ops = &usb_log_ops;
@ -66,13 +68,17 @@ int diag_mux_init()
* Set USB logging as the default logger. This is the mode * Set USB logging as the default logger. This is the mode
* Diag should be in when it initializes. * Diag should be in when it initializes.
*/ */
logger = &usb_logger; diag_mux->usb_ptr = &usb_logger;
diag_mux->md_ptr = &md_logger;
diag_mux->logger = &usb_logger;
diag_mux->mux_mask = 0;
diag_mux->mode = DIAG_USB_MODE;
return 0; return 0;
} }
void diag_mux_exit() void diag_mux_exit()
{ {
kfree(logger); kfree(diag_mux);
} }
int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops) int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops)
@ -106,19 +112,43 @@ int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops)
int diag_mux_queue_read(int proc) int diag_mux_queue_read(int proc)
{ {
struct diag_logger_t *logger = NULL;
if (proc < 0 || proc >= NUM_MUX_PROC) if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL; return -EINVAL;
if (!logger) if (!diag_mux)
return -EIO; return -EIO;
if (logger->log_ops && logger->log_ops->queue_read)
if (diag_mux->mode == DIAG_MULTI_MODE)
logger = diag_mux->usb_ptr;
else
logger = diag_mux->logger;
if (logger && logger->log_ops && logger->log_ops->queue_read)
return logger->log_ops->queue_read(proc); return logger->log_ops->queue_read(proc);
return 0; return 0;
} }
int diag_mux_write(int proc, unsigned char *buf, int len, int ctx) int diag_mux_write(int proc, unsigned char *buf, int len, int ctx)
{ {
struct diag_logger_t *logger = NULL;
int peripheral;
if (proc < 0 || proc >= NUM_MUX_PROC) if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL; return -EINVAL;
if (!diag_mux)
return -EIO;
peripheral = GET_BUF_PERIPHERAL(ctx);
if (peripheral > NUM_PERIPHERALS)
return -EINVAL;
if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
logger = diag_mux->md_ptr;
else
logger = diag_mux->usb_ptr;
if (logger && logger->log_ops && logger->log_ops->write) if (logger && logger->log_ops && logger->log_ops->write)
return logger->log_ops->write(proc, buf, len, ctx); return logger->log_ops->write(proc, buf, len, ctx);
return 0; return 0;
@ -126,38 +156,86 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx)
int diag_mux_close_peripheral(int proc, uint8_t peripheral) int diag_mux_close_peripheral(int proc, uint8_t peripheral)
{ {
struct diag_logger_t *logger = NULL;
if (proc < 0 || proc >= NUM_MUX_PROC) if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL; return -EINVAL;
/* Peripheral should account for Apps data as well */ /* Peripheral should account for Apps data as well */
if (peripheral > NUM_PERIPHERALS) if (peripheral > NUM_PERIPHERALS)
return -EINVAL; return -EINVAL;
if (!diag_mux)
return -EIO;
if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
logger = diag_mux->md_ptr;
else
logger = diag_mux->logger;
if (logger && logger->log_ops && logger->log_ops->close_peripheral) if (logger && logger->log_ops && logger->log_ops->close_peripheral)
return logger->log_ops->close_peripheral(proc, peripheral); return logger->log_ops->close_peripheral(proc, peripheral);
return 0; return 0;
} }
int diag_mux_switch_logging(int new_mode) int diag_mux_switch_logging(int *req_mode, int *peripheral_mask)
{ {
struct diag_logger_t *new_logger = NULL; unsigned int new_mask = 0;
switch (new_mode) { if (!req_mode)
case DIAG_USB_MODE: return -EINVAL;
new_logger = &usb_logger;
break; if (*peripheral_mask <= 0 || *peripheral_mask > DIAG_CON_ALL) {
case DIAG_MEMORY_DEVICE_MODE: pr_err("diag: mask %d in %s\n", *peripheral_mask, __func__);
new_logger = &md_logger;
break;
default:
pr_err("diag: Invalid mode %d in %s\n", new_mode, __func__);
return -EINVAL; return -EINVAL;
} }
if (logger) { switch (*req_mode) {
logger->log_ops->close(); case DIAG_USB_MODE:
logger = new_logger; new_mask = ~(*peripheral_mask) & diag_mux->mux_mask;
logger->log_ops->open(); if (new_mask != DIAG_CON_NONE)
*req_mode = DIAG_MULTI_MODE;
break;
case DIAG_MEMORY_DEVICE_MODE:
new_mask = (*peripheral_mask) | diag_mux->mux_mask;
if (new_mask != DIAG_CON_ALL)
*req_mode = DIAG_MULTI_MODE;
break;
default:
pr_err("diag: Invalid mode %d in %s\n", *req_mode, __func__);
return -EINVAL;
} }
switch (diag_mux->mode) {
case DIAG_USB_MODE:
if (*req_mode == DIAG_MEMORY_DEVICE_MODE) {
diag_mux->usb_ptr->log_ops->close();
diag_mux->logger = diag_mux->md_ptr;
diag_mux->md_ptr->log_ops->open();
} else if (*req_mode == DIAG_MULTI_MODE) {
diag_mux->md_ptr->log_ops->open();
diag_mux->logger = NULL;
}
break;
case DIAG_MEMORY_DEVICE_MODE:
if (*req_mode == DIAG_USB_MODE) {
diag_mux->md_ptr->log_ops->close();
diag_mux->logger = diag_mux->usb_ptr;
diag_mux->usb_ptr->log_ops->open();
} else if (*req_mode == DIAG_MULTI_MODE) {
diag_mux->usb_ptr->log_ops->open();
diag_mux->logger = NULL;
}
break;
case DIAG_MULTI_MODE:
if (*req_mode == DIAG_USB_MODE) {
diag_mux->md_ptr->log_ops->close();
diag_mux->logger = diag_mux->usb_ptr;
} else if (*req_mode == DIAG_MEMORY_DEVICE_MODE) {
diag_mux->usb_ptr->log_ops->close();
diag_mux->logger = diag_mux->md_ptr;
}
break;
}
diag_mux->mode = *req_mode;
diag_mux->mux_mask = new_mask;
*peripheral_mask = new_mask;
return 0; return 0;
} }

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -13,6 +13,14 @@
#define DIAG_MUX_H #define DIAG_MUX_H
#include "diagchar.h" #include "diagchar.h"
struct diag_mux_state_t {
struct diag_logger_t *logger;
struct diag_logger_t *usb_ptr;
struct diag_logger_t *md_ptr;
unsigned int mux_mask;
unsigned int mode;
};
struct diag_mux_ops { struct diag_mux_ops {
int (*open)(int id, int mode); int (*open)(int id, int mode);
int (*close)(int id, int mode); int (*close)(int id, int mode);
@ -24,6 +32,7 @@ struct diag_mux_ops {
#define DIAG_USB_MODE 0 #define DIAG_USB_MODE 0
#define DIAG_MEMORY_DEVICE_MODE 1 #define DIAG_MEMORY_DEVICE_MODE 1
#define DIAG_NO_LOGGING_MODE 2 #define DIAG_NO_LOGGING_MODE 2
#define DIAG_MULTI_MODE 3
#define DIAG_MUX_LOCAL 0 #define DIAG_MUX_LOCAL 0
#define DIAG_MUX_LOCAL_LAST 1 #define DIAG_MUX_LOCAL_LAST 1
@ -53,7 +62,7 @@ struct diag_logger_t {
struct diag_logger_ops *log_ops; struct diag_logger_ops *log_ops;
}; };
extern struct diag_logger_t *logger; extern struct diag_mux_state_t *diag_mux;
int diag_mux_init(void); int diag_mux_init(void);
void diag_mux_exit(void); void diag_mux_exit(void);
@ -63,5 +72,5 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx);
int diag_mux_close_peripheral(int proc, uint8_t peripheral); int diag_mux_close_peripheral(int proc, uint8_t peripheral);
int diag_mux_open_all(struct diag_logger_t *logger); int diag_mux_open_all(struct diag_logger_t *logger);
int diag_mux_close_all(void); int diag_mux_close_all(void);
int diag_mux_switch_logging(int new_mode); int diag_mux_switch_logging(int *new_mode, int *peripheral_mask);
#endif #endif

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -59,11 +59,15 @@
#define DIAG_CTRL_MSG_F3_MASK 11 #define DIAG_CTRL_MSG_F3_MASK 11
#define CONTROL_CHAR 0x7E #define CONTROL_CHAR 0x7E
#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */ #define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */
#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */ #define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */ #define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */ #define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
#define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */ #define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */
#define DIAG_CON_NONE (0x0000) /* Bit mask for No SS*/
#define DIAG_CON_ALL (DIAG_CON_APSS | DIAG_CON_MPSS \
| DIAG_CON_LPASS | DIAG_CON_WCNSS \
| DIAG_CON_SENSORS)
#define DIAG_STM_MODEM 0x01 #define DIAG_STM_MODEM 0x01
#define DIAG_STM_LPASS 0x02 #define DIAG_STM_LPASS 0x02
@ -158,8 +162,7 @@
#define FEATURE_MASK_LEN 2 #define FEATURE_MASK_LEN 2
#define DIAG_MD_NONE 0 #define DIAG_MD_NONE 0
#define DIAG_MD_NORMAL 1 #define DIAG_MD_PERIPHERAL 1
#define DIAG_MD_PERIPHERAL 2
/* /*
* The status bit masks when received in a signal handler are to be * The status bit masks when received in a signal handler are to be
@ -561,6 +564,7 @@ struct diagchar_dev {
uint32_t dci_pkt_length; uint32_t dci_pkt_length;
int in_busy_dcipktdata; int in_busy_dcipktdata;
int logging_mode; int logging_mode;
int logging_mask;
int mask_check; int mask_check;
uint32_t md_session_mask; uint32_t md_session_mask;
uint8_t md_session_mode; uint8_t md_session_mode;

View file

@ -369,6 +369,24 @@ fail:
return -ENOMEM; return -ENOMEM;
} }
static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask)
{
uint32_t ret = 0;
if (peripheral_mask & MD_PERIPHERAL_MASK(APPS_DATA))
ret |= DIAG_CON_APSS;
if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_MODEM))
ret |= DIAG_CON_MPSS;
if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_LPASS))
ret |= DIAG_CON_LPASS;
if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_WCNSS))
ret |= DIAG_CON_WCNSS;
if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_SENSORS))
ret |= DIAG_CON_SENSORS;
return ret;
}
static void diag_close_logging_process(const int pid) static void diag_close_logging_process(const int pid)
{ {
int i; int i;
@ -388,7 +406,8 @@ static void diag_close_logging_process(const int pid)
params.req_mode = USB_MODE; params.req_mode = USB_MODE;
params.mode_param = 0; params.mode_param = 0;
params.peripheral_mask = 0; params.peripheral_mask =
diag_translate_kernel_to_user_mask(session_peripheral_mask);
mutex_lock(&driver->diagchar_mutex); mutex_lock(&driver->diagchar_mutex);
diag_switch_logging(&params); diag_switch_logging(&params);
mutex_unlock(&driver->diagchar_mutex); mutex_unlock(&driver->diagchar_mutex);
@ -417,10 +436,11 @@ static int diag_remove_client_entry(struct file *file)
diagpriv_data = file->private_data; diagpriv_data = file->private_data;
/* clean up any DCI registrations, if this is a DCI client /*
* This will specially help in case of ungraceful exit of any DCI client * clean up any DCI registrations, if this is a DCI client
* This call will remove any pending registrations of such client * This will specially help in case of ungraceful exit of any DCI client
*/ * This call will remove any pending registrations of such client
*/
mutex_lock(&driver->dci_mutex); mutex_lock(&driver->dci_mutex);
dci_entry = dci_lookup_client_entry_pid(current->tgid); dci_entry = dci_lookup_client_entry_pid(current->tgid);
if (dci_entry) if (dci_entry)
@ -1148,19 +1168,10 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc)
struct diag_md_session_t *new_session = NULL; struct diag_md_session_t *new_session = NULL;
/* /*
* If there is any session running in Normal mode * If a session is running with a peripheral mask and a new session
* we cannot start a new session . If there is a * request comes in with same peripheral mask value then return
* session running in Peripheral mode we cannot * invalid param
* start a new session in NORMAL mode. If a session is
* running with a peripheral mask and a new session
* request comes in with same peripheral mask value
* then return invalid param
*/ */
if (driver->md_session_mode == DIAG_MD_NORMAL)
return -EINVAL;
if (driver->md_session_mode == DIAG_MD_PERIPHERAL
&& mode == DIAG_MD_NORMAL)
return -EINVAL;
if (driver->md_session_mode == DIAG_MD_PERIPHERAL && if (driver->md_session_mode == DIAG_MD_PERIPHERAL &&
(driver->md_session_mask & peripheral_mask) != 0) (driver->md_session_mask & peripheral_mask) != 0)
return -EINVAL; return -EINVAL;
@ -1176,32 +1187,6 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc)
new_session->pid = current->tgid; new_session->pid = current->tgid;
new_session->task = current; new_session->task = current;
if (mode == DIAG_MD_NORMAL) {
new_session->log_mask = &log_mask;
new_session->event_mask = &event_mask;
new_session->msg_mask = &msg_mask;
for (i = 0; i < NUM_MD_SESSIONS; i++) {
if (driver->md_session_map[i] != NULL) {
DIAG_LOG(DIAG_DEBUG_USERSPACE,
"another instance present for %d\n",
i);
err = -EEXIST;
goto fail_normal;
}
new_session->peripheral_mask |= MD_PERIPHERAL_MASK(i);
driver->md_session_mask |= MD_PERIPHERAL_MASK(i);
driver->md_session_map[i] = new_session;
}
driver->md_session_mode = DIAG_MD_NORMAL;
setup_timer(&new_session->hdlc_reset_timer,
diag_md_hdlc_reset_timer_func,
new_session->pid);
DIAG_LOG(DIAG_DEBUG_USERSPACE,
"created session in normal mode\n");
mutex_unlock(&driver->md_session_lock);
return 0;
}
new_session->log_mask = kzalloc(sizeof(struct diag_mask_info), new_session->log_mask = kzalloc(sizeof(struct diag_mask_info),
GFP_KERNEL); GFP_KERNEL);
if (!new_session->log_mask) { if (!new_session->log_mask) {
@ -1251,10 +1236,11 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc)
new_session->peripheral_mask |= MD_PERIPHERAL_MASK(i); new_session->peripheral_mask |= MD_PERIPHERAL_MASK(i);
driver->md_session_map[i] = new_session; driver->md_session_map[i] = new_session;
driver->md_session_mask |= MD_PERIPHERAL_MASK(i); driver->md_session_mask |= MD_PERIPHERAL_MASK(i);
setup_timer(&new_session->hdlc_reset_timer,
diag_md_hdlc_reset_timer_func,
new_session->pid);
} }
setup_timer(&new_session->hdlc_reset_timer,
diag_md_hdlc_reset_timer_func,
new_session->pid);
driver->md_session_mode = DIAG_MD_PERIPHERAL; driver->md_session_mode = DIAG_MD_PERIPHERAL;
mutex_unlock(&driver->md_session_lock); mutex_unlock(&driver->md_session_lock);
DIAG_LOG(DIAG_DEBUG_USERSPACE, DIAG_LOG(DIAG_DEBUG_USERSPACE,
@ -1271,7 +1257,6 @@ fail_peripheral:
diag_msg_mask_free(new_session->msg_mask); diag_msg_mask_free(new_session->msg_mask);
kfree(new_session->msg_mask); kfree(new_session->msg_mask);
new_session->msg_mask = NULL; new_session->msg_mask = NULL;
fail_normal:
kfree(new_session); kfree(new_session);
new_session = NULL; new_session = NULL;
mutex_unlock(&driver->md_session_lock); mutex_unlock(&driver->md_session_lock);
@ -1292,19 +1277,17 @@ static void diag_md_session_close(struct diag_md_session_t *session_info)
continue; continue;
driver->md_session_map[i] = NULL; driver->md_session_map[i] = NULL;
driver->md_session_mask &= ~session_info->peripheral_mask; driver->md_session_mask &= ~session_info->peripheral_mask;
if (driver->md_session_mode == DIAG_MD_NORMAL)
continue;
diag_log_mask_free(session_info->log_mask);
kfree(session_info->log_mask);
session_info->log_mask = NULL;
diag_msg_mask_free(session_info->msg_mask);
kfree(session_info->msg_mask);
session_info->msg_mask = NULL;
diag_event_mask_free(session_info->event_mask);
kfree(session_info->event_mask);
session_info->event_mask = NULL;
del_timer(&session_info->hdlc_reset_timer);
} }
diag_log_mask_free(session_info->log_mask);
kfree(session_info->log_mask);
session_info->log_mask = NULL;
diag_msg_mask_free(session_info->msg_mask);
kfree(session_info->msg_mask);
session_info->msg_mask = NULL;
diag_event_mask_free(session_info->event_mask);
kfree(session_info->event_mask);
session_info->event_mask = NULL;
del_timer(&session_info->hdlc_reset_timer);
for (i = 0; i < NUM_MD_SESSIONS && !found; i++) { for (i = 0; i < NUM_MD_SESSIONS && !found; i++) {
if (driver->md_session_map[i] != NULL) if (driver->md_session_map[i] != NULL)
@ -1337,113 +1320,157 @@ struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral)
return driver->md_session_map[peripheral]; return driver->md_session_map[peripheral];
} }
static int diag_md_peripheral_switch(struct diag_md_session_t *session_info,
int peripheral_mask, int req_mode) {
int i, bit = 0;
if (!session_info)
return -EINVAL;
if (req_mode != DIAG_USB_MODE || req_mode != DIAG_MEMORY_DEVICE_MODE)
return -EINVAL;
/*
* check that md_session_map for i == session_info,
* if not then race condition occurred and bail
*/
mutex_lock(&driver->md_session_lock);
for (i = 0; i < NUM_MD_SESSIONS; i++) {
bit = MD_PERIPHERAL_MASK(i) & peripheral_mask;
if (!bit)
continue;
if (req_mode == DIAG_USB_MODE) {
if (driver->md_session_map[i] != session_info) {
mutex_unlock(&driver->md_session_lock);
return -EINVAL;
}
driver->md_session_map[i] = NULL;
driver->md_session_mask &= ~bit;
session_info->peripheral_mask &= ~bit;
} else {
if (driver->md_session_map[i] != NULL) {
mutex_unlock(&driver->md_session_lock);
return -EINVAL;
}
driver->md_session_map[i] = session_info;
driver->md_session_mask |= bit;
session_info->peripheral_mask |= bit;
}
}
driver->md_session_mode = DIAG_MD_PERIPHERAL;
mutex_unlock(&driver->md_session_lock);
DIAG_LOG(DIAG_DEBUG_USERSPACE, "Changed Peripherals:0x%x to mode:%d\n",
peripheral_mask, req_mode);
}
static int diag_md_session_check(int curr_mode, int req_mode, static int diag_md_session_check(int curr_mode, int req_mode,
const struct diag_logging_mode_param_t *param, const struct diag_logging_mode_param_t *param,
uint8_t *change_mode) uint8_t *change_mode)
{ {
int err = 0; int i, bit = 0, err = 0;
int change_mask = 0;
struct diag_md_session_t *session_info = NULL; struct diag_md_session_t *session_info = NULL;
if (!param || !change_mode) if (!param || !change_mode)
return -EIO; return -EIO;
*change_mode = 1; *change_mode = 0;
switch (curr_mode) { switch (curr_mode) {
case DIAG_USB_MODE: case DIAG_USB_MODE:
case DIAG_MEMORY_DEVICE_MODE: case DIAG_MEMORY_DEVICE_MODE:
case DIAG_MULTI_MODE:
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
switch (req_mode) { if (req_mode != DIAG_USB_MODE && req_mode != DIAG_MEMORY_DEVICE_MODE)
case DIAG_USB_MODE:
case DIAG_MEMORY_DEVICE_MODE:
break;
default:
return -EINVAL; return -EINVAL;
}
if (curr_mode == DIAG_USB_MODE) { if (req_mode == DIAG_USB_MODE) {
if (req_mode == DIAG_USB_MODE) { if (curr_mode == DIAG_USB_MODE)
/* return 0;
* This case tries to change from USB mode to USB mode. if (driver->md_session_mode == DIAG_MD_NONE
* There is no change required. Return success. && driver->md_session_mask == 0 && driver->logging_mask) {
*/ *change_mode = 1;
*change_mode = 0;
return 0; return 0;
} }
/* /*
* If there is no other mdlog process, return success. * curr_mode is either DIAG_MULTI_MODE or DIAG_MD_MODE
* Check if the peripheral interested in is active. * Check if requested peripherals are already in usb mode
*/ */
if (param->mode_param == DIAG_MD_NORMAL) { for (i = 0; i < NUM_MD_SESSIONS; i++) {
err = diag_md_session_create(DIAG_MD_NORMAL, 0, bit = MD_PERIPHERAL_MASK(i) & param->peripheral_mask;
DIAG_LOCAL_PROC); if (!bit)
return err; continue;
} else if (param->mode_param == DIAG_MD_PERIPHERAL && if (bit & driver->logging_mask)
(!(driver->md_session_mask & change_mask |= bit;
param->peripheral_mask))) {
err = diag_md_session_create(DIAG_MD_PERIPHERAL,
param->peripheral_mask,
DIAG_LOCAL_PROC);
return err;
} }
DIAG_LOG(DIAG_DEBUG_USERSPACE, if (!change_mask)
"an instance of mdlog is active\n"); return 0;
*change_mode = 0;
return -EINVAL; /*
} else if (curr_mode == DIAG_MEMORY_DEVICE_MODE) { * Change is needed. Check if this md_session has set all the
if (req_mode == DIAG_USB_MODE) { * requested peripherals. If another md session set a requested
if (driver->md_session_mask != 0 && * peripheral then we cannot switch that peripheral to USB.
driver->md_session_mode == DIAG_MD_PERIPHERAL) { * If this session owns all the requested peripherals, then
/* * call function to switch the modes/masks for the md_session
* An instance of mdlog is still running, Return */
* error. session_info = diag_md_session_get_pid(current->tgid);
*/ if (!session_info) {
DIAG_LOG(DIAG_DEBUG_USERSPACE, *change_mode = 1;
"another instance running\n");
*change_mode = 0;
return -EINVAL;
}
session_info = diag_md_session_get_pid(current->tgid);
diag_md_session_close(session_info);
return 0; return 0;
} }
if ((change_mask & session_info->peripheral_mask)
if (param->mode_param == DIAG_MD_NORMAL) { != change_mask) {
/*
* The new client is asking for MD_NORMAL. We're
* already in memory device mode - this must be
* set by another active process. Return error
* for this new client.
*/
DIAG_LOG(DIAG_DEBUG_USERSPACE, DIAG_LOG(DIAG_DEBUG_USERSPACE,
"unable to switch logging mode\n"); "Another MD Session owns a requested peripheral\n");
*change_mode = 0;
return -EINVAL; return -EINVAL;
} else if (param->mode_param == DIAG_MD_PERIPHERAL) { }
if (driver->md_session_mask & param->peripheral_mask) { *change_mode = 1;
/*
* The new client is asking for a /* If all peripherals are being set to USB Mode, call close */
* specific peripheral. This case checks if (~change_mask & session_info->peripheral_mask) {
* if a client is exercising this err = diag_md_peripheral_switch(session_info,
* peripheral already. Return error change_mask, DIAG_USB_MODE);
* if the peripheral is already in use. } else
*/ diag_md_session_close(session_info);
return err;
} else if (req_mode == DIAG_MEMORY_DEVICE_MODE) {
/*
* Get bit mask that represents what peripherals already have
* been set. Check that requested peripherals already set are
* owned by this md session
*/
change_mask = driver->md_session_mask & param->peripheral_mask;
session_info = diag_md_session_get_pid(current->tgid);
if (session_info) {
if ((session_info->peripheral_mask & change_mask)
!= change_mask) {
DIAG_LOG(DIAG_DEBUG_USERSPACE, DIAG_LOG(DIAG_DEBUG_USERSPACE,
"another instance running\n"); "Another MD Session owns a requested peripheral\n");
*change_mode = 0; return -EINVAL;
}
err = diag_md_peripheral_switch(session_info,
change_mask, DIAG_USB_MODE);
} else {
if (change_mask) {
DIAG_LOG(DIAG_DEBUG_USERSPACE,
"Another MD Session owns a requested peripheral\n");
return -EINVAL; return -EINVAL;
} }
err = diag_md_session_create(DIAG_MD_PERIPHERAL, err = diag_md_session_create(DIAG_MD_PERIPHERAL,
param->peripheral_mask, param->peripheral_mask, DIAG_LOCAL_PROC);
DIAG_LOCAL_PROC);
*change_mode = 0;
return err;
} }
*change_mode = 1;
return err;
} }
return -EINVAL; return -EINVAL;
} }
@ -1477,17 +1504,14 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
if (!param) if (!param)
return -EINVAL; return -EINVAL;
if (param->mode_param == DIAG_MD_PERIPHERAL && if (!param->peripheral_mask) {
param->peripheral_mask == 0) {
DIAG_LOG(DIAG_DEBUG_USERSPACE, DIAG_LOG(DIAG_DEBUG_USERSPACE,
"asking for peripehral mode with no mask being set\n"); "asking for mode switch with no peripheral mask set\n");
return -EINVAL; return -EINVAL;
} }
if (param->mode_param == DIAG_MD_PERIPHERAL) { peripheral_mask = diag_translate_mask(param->peripheral_mask);
peripheral_mask = diag_translate_mask(param->peripheral_mask); param->peripheral_mask = peripheral_mask;
param->peripheral_mask = peripheral_mask;
}
switch (param->req_mode) { switch (param->req_mode) {
case CALLBACK_MODE: case CALLBACK_MODE:
@ -1507,8 +1531,8 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
curr_mode = driver->logging_mode; curr_mode = driver->logging_mode;
DIAG_LOG(DIAG_DEBUG_USERSPACE, DIAG_LOG(DIAG_DEBUG_USERSPACE,
"request to switch logging from: %d to %d\n", "request to switch logging from %d mask:%0x to %d mask:%0x\n",
curr_mode, new_mode); curr_mode, driver->md_session_mask, new_mode, peripheral_mask);
err = diag_md_session_check(curr_mode, new_mode, param, &do_switch); err = diag_md_session_check(curr_mode, new_mode, param, &do_switch);
if (err) { if (err) {
@ -1525,7 +1549,7 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
} }
diag_ws_reset(DIAG_WS_MUX); diag_ws_reset(DIAG_WS_MUX);
err = diag_mux_switch_logging(new_mode); err = diag_mux_switch_logging(&new_mode, &peripheral_mask);
if (err) { if (err) {
pr_err("diag: In %s, unable to switch mode from %d to %d, err: %d\n", pr_err("diag: In %s, unable to switch mode from %d to %d, err: %d\n",
__func__, curr_mode, new_mode, err); __func__, curr_mode, new_mode, err);
@ -1533,7 +1557,11 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
goto fail; goto fail;
} }
driver->logging_mode = new_mode; driver->logging_mode = new_mode;
driver->logging_mask = peripheral_mask;
DIAG_LOG(DIAG_DEBUG_USERSPACE,
"Switch logging to %d mask:%0x\n", new_mode, peripheral_mask);
/* Update to take peripheral_mask */
if (new_mode != DIAG_MEMORY_DEVICE_MODE) { if (new_mode != DIAG_MEMORY_DEVICE_MODE) {
diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE, diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE,
MODE_REALTIME, ALL_PROC); MODE_REALTIME, ALL_PROC);
@ -1839,10 +1867,8 @@ static int diag_ioctl_register_callback(unsigned long ioarg)
return -EINVAL; return -EINVAL;
} }
if (driver->md_session_mode == DIAG_MD_NORMAL || if (driver->md_session_mode == DIAG_MD_PERIPHERAL)
driver->md_session_mode == DIAG_MD_PERIPHERAL) {
return -EIO; return -EIO;
}
return err; return err;
} }
@ -2737,7 +2763,8 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
mutex_lock(&driver->diagchar_mutex); mutex_lock(&driver->diagchar_mutex);
if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) &&
(driver->logging_mode == DIAG_MEMORY_DEVICE_MODE)) { (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
driver->logging_mode == DIAG_MULTI_MODE)) {
pr_debug("diag: process woken up\n"); pr_debug("diag: process woken up\n");
/*Copy the type of data being passed*/ /*Copy the type of data being passed*/
data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE; data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;

View file

@ -234,7 +234,7 @@ void chk_logging_wakeup(void)
* index as all the indices point to the same session * index as all the indices point to the same session
* structure. * structure.
*/ */
if (driver->md_session_mode == DIAG_MD_NORMAL && j == 0) if ((driver->md_session_mask == DIAG_CON_ALL) && (j == 0))
break; break;
} }
} }
@ -278,7 +278,8 @@ static void pack_rsp_and_send(unsigned char *buf, int len)
* for responses. Make sure we don't miss previous wakeups for * for responses. Make sure we don't miss previous wakeups for
* draining responses when we are in Memory Device Mode. * draining responses when we are in Memory Device Mode.
*/ */
if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
driver->logging_mode == DIAG_MULTI_MODE)
chk_logging_wakeup(); chk_logging_wakeup();
} }
if (driver->rsp_buf_busy) { if (driver->rsp_buf_busy) {
@ -346,7 +347,8 @@ static void encode_rsp_and_send(unsigned char *buf, int len)
* for responses. Make sure we don't miss previous wakeups for * for responses. Make sure we don't miss previous wakeups for
* draining responses when we are in Memory Device Mode. * draining responses when we are in Memory Device Mode.
*/ */
if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
driver->logging_mode == DIAG_MULTI_MODE)
chk_logging_wakeup(); chk_logging_wakeup();
} }
@ -919,8 +921,13 @@ int diag_process_apps_pkt(unsigned char *buf, int len,
if (MD_PERIPHERAL_MASK(reg_item->proc) & if (MD_PERIPHERAL_MASK(reg_item->proc) &
info->peripheral_mask) info->peripheral_mask)
write_len = diag_send_data(reg_item, buf, len); write_len = diag_send_data(reg_item, buf, len);
} else } else {
write_len = diag_send_data(reg_item, buf, len); if (MD_PERIPHERAL_MASK(reg_item->proc) &
driver->logging_mask)
diag_send_error_rsp(buf, len);
else
write_len = diag_send_data(reg_item, buf, len);
}
mutex_unlock(&driver->cmd_reg_mutex); mutex_unlock(&driver->cmd_reg_mutex);
return write_len; return write_len;
} }
@ -1228,10 +1235,9 @@ static int diagfwd_mux_close(int id, int mode)
return -EINVAL; return -EINVAL;
} }
if ((mode == DIAG_USB_MODE && if ((driver->logging_mode == DIAG_MULTI_MODE &&
driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) || driver->md_session_mode == DIAG_MD_NONE) ||
(mode == DIAG_MEMORY_DEVICE_MODE && (driver->md_session_mode == DIAG_MD_PERIPHERAL)) {
driver->logging_mode == DIAG_USB_MODE)) {
/* /*
* In this case the channel must not be closed. This case * In this case the channel must not be closed. This case
* indicates that the USB is removed but there is a client * indicates that the USB is removed but there is a client