118 lines
4 KiB
C
Executable file
118 lines
4 KiB
C
Executable file
/****************************************************************************
|
|
*
|
|
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "dev.h"
|
|
#include "debug.h"
|
|
#include "udi.h"
|
|
#include "log_clients.h"
|
|
#include "unifiio.h"
|
|
|
|
/* These functions should NOT be called from interrupt context */
|
|
/* It is supposed to be called from process context, or
|
|
* NET_TX_SOFTIRQ - with BHs disabled and interrupts disabled
|
|
*/
|
|
/* Do not sleep */
|
|
|
|
void slsi_log_clients_log_signal_safe(struct slsi_dev *sdev, struct sk_buff *skb, u32 direction)
|
|
{
|
|
struct list_head *pos, *n;
|
|
struct slsi_log_client *log_client;
|
|
int dir = (direction == SLSI_LOG_DIRECTION_FROM_HOST) ? UDI_FROM_HOST : UDI_TO_HOST;
|
|
|
|
spin_lock_bh(&sdev->log_clients.log_client_spinlock);
|
|
list_for_each_safe(pos, n, &sdev->log_clients.log_client_list) {
|
|
log_client = list_entry(pos, struct slsi_log_client, q);
|
|
log_client->log_client_cb(log_client, skb, dir);
|
|
}
|
|
spin_unlock_bh(&sdev->log_clients.log_client_spinlock);
|
|
}
|
|
|
|
void slsi_log_clients_init(struct slsi_dev *sdev)
|
|
{
|
|
INIT_LIST_HEAD(&sdev->log_clients.log_client_list);
|
|
spin_lock_init(&sdev->log_clients.log_client_spinlock);
|
|
}
|
|
|
|
/* The arg called "filter" will eventually be passed to kfree().
|
|
* - so pass a NULL if you are not doing any filtering
|
|
*/
|
|
int slsi_log_client_register(struct slsi_dev *sdev, void *log_client_ctx,
|
|
int (*log_client_cb)(struct slsi_log_client *, struct sk_buff *, int),
|
|
char *filter, int min_signal_id, int max_signal_id)
|
|
{
|
|
struct slsi_log_client *log_client;
|
|
int first_in_list = 0;
|
|
|
|
first_in_list = list_empty(&sdev->log_clients.log_client_list);
|
|
log_client = kmalloc(sizeof(*log_client), GFP_KERNEL);
|
|
if (log_client == NULL)
|
|
return -ENOMEM;
|
|
|
|
log_client->min_signal_id = min_signal_id;
|
|
log_client->max_signal_id = max_signal_id;
|
|
log_client->signal_filter = filter;
|
|
log_client->log_client_ctx = log_client_ctx;
|
|
log_client->log_client_cb = log_client_cb;
|
|
|
|
/* Add to tail of log queue */
|
|
spin_lock_bh(&sdev->log_clients.log_client_spinlock);
|
|
list_add_tail(&log_client->q, &sdev->log_clients.log_client_list);
|
|
spin_unlock_bh(&sdev->log_clients.log_client_spinlock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void slsi_log_clients_terminate(struct slsi_dev *sdev)
|
|
{
|
|
/* If the driver is configured to try and terminate UDI user space
|
|
* applications, the following will try to do so.
|
|
*/
|
|
if (*sdev->term_udi_users) {
|
|
int num_polls_left = 50;
|
|
unsigned int timeout_ms = 4;
|
|
|
|
slsi_log_client_msg(sdev, UDI_DRV_UNLOAD_IND, 0, NULL);
|
|
|
|
/* Poll until all refs have gone away or timeout */
|
|
while (slsi_check_cdev_refs() && num_polls_left) {
|
|
msleep(timeout_ms);
|
|
num_polls_left--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void slsi_log_client_msg(struct slsi_dev *sdev, u16 event, u32 event_data_length, const u8 *event_data)
|
|
{
|
|
struct list_head *pos, *n;
|
|
struct slsi_log_client *log_client;
|
|
|
|
spin_lock_bh(&sdev->log_clients.log_client_spinlock);
|
|
list_for_each_safe(pos, n, &sdev->log_clients.log_client_list) {
|
|
log_client = list_entry(pos, struct slsi_log_client, q);
|
|
spin_unlock_bh(&sdev->log_clients.log_client_spinlock);
|
|
if (slsi_kernel_to_user_space_event(log_client, event, event_data_length, event_data))
|
|
SLSI_WARN(sdev, "Failed to send event(0x%.4X) to UDI client 0x%p\n", event, log_client);
|
|
spin_lock_bh(&sdev->log_clients.log_client_spinlock);
|
|
}
|
|
spin_unlock_bh(&sdev->log_clients.log_client_spinlock);
|
|
}
|
|
|
|
void slsi_log_client_unregister(struct slsi_dev *sdev, void *log_client_ctx)
|
|
{
|
|
struct list_head *pos, *n;
|
|
struct slsi_log_client *log_client;
|
|
|
|
spin_lock_bh(&sdev->log_clients.log_client_spinlock);
|
|
list_for_each_safe(pos, n, &sdev->log_clients.log_client_list) {
|
|
log_client = list_entry(pos, struct slsi_log_client, q);
|
|
if (log_client->log_client_ctx == log_client_ctx) {
|
|
kfree(log_client->signal_filter);
|
|
list_del(pos);
|
|
kfree(log_client);
|
|
}
|
|
}
|
|
spin_unlock_bh(&sdev->log_clients.log_client_spinlock);
|
|
}
|