mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 15:28:50 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
119
drivers/net/wireless/scsc/test/Makefile
Normal file
119
drivers/net/wireless/scsc/test/Makefile
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# ----------------------------------------------------------------------------
|
||||
# FILE: Makefile
|
||||
#
|
||||
# PURPOSE:
|
||||
# Build instructions for SCSC Wlan driver.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 2016 by Samsung Electronics Co., Ltd
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
CONFIG_SCSC_WLAN_MODULE=scsc_wlan_unittest
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Common Driver Files
|
||||
# ----------------------------------------------------------------------------
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../mib.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../mib_text_convert.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../debug.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../debug_frame.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../procfs.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../mgt.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../udi.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../log_clients.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../src_sink.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../fw_test.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../cac.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../ioctl.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../wakelock.o
|
||||
|
||||
# enable Oxygen
|
||||
ifeq ($(CONFIG_SCSC_WLAN_OXYGEN_ENABLE),y)
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../oxygen_ioctl.o
|
||||
endif
|
||||
|
||||
# enable GSCAN
|
||||
ifeq ($(CONFIG_SCSC_WLAN_GSCAN_ENABLE),y)
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../nl80211_vendor.o
|
||||
ccflags-y += -DCONFIG_SCSC_WLAN_GSCAN_ENABLE
|
||||
endif
|
||||
|
||||
# enable roam offload
|
||||
ifeq ($(CONFIG_SCSC_WLAN_KEY_MGMT_OFFLOAD),y)
|
||||
ccflags-y += -DCONFIG_SCSC_WLAN_KEY_MGMT_OFFLOAD
|
||||
endif
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Building for cfg802.11
|
||||
# ----------------------------------------------------------------------------
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../cfg80211_ops.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../mlme.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../netif.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../rx.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../tx.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../ba.o
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Building for SAP
|
||||
# ----------------------------------------------------------------------------
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../sap_ma.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../sap_mlme.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../sap_dbg.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../sap_test.o
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# unittest Driver
|
||||
# ----------------------------------------------------------------------------
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += ../dev.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += dev_test.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += hip_test.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += hydra_test.o
|
||||
$(CONFIG_SCSC_WLAN_MODULE)-y += udi_test.o
|
||||
|
||||
# Suppress -Wempty-body when not built with Debug enabled.
|
||||
ifneq ($(CONFIG_SCSC_WLAN_DEBUG),y)
|
||||
ccflags-y += -Wno-empty-body
|
||||
else
|
||||
ccflags-y += -g -ggdb
|
||||
endif
|
||||
|
||||
ccflags-y += -Wno-unused-parameter
|
||||
ccflags-y += -Wno-sign-compare
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# wlan configuration
|
||||
# ----------------------------------------------------------------------------
|
||||
ccflags-$(CONFIG_SCSC_WLAN_DEBUG) += -DCONFIG_SCSC_WLAN_DEBUG
|
||||
ccflags-$(CONFIG_SCSC_WLAN_SKB_TRACKING) += -DCONFIG_SCSC_WLAN_SKB_TRACKING
|
||||
ccflags-$(CONFIG_SCSC_WLAN_OFFLINE_TRACE) += -DCONFIG_SCSC_WLAN_OFFLINE_TRACE
|
||||
ccflags-$(CONFIG_SCSC_WLAN_OFFLINE_SDIO_TRACE) += -DCONFIG_SCSC_WLAN_OFFLINE_SDIO_TRACE
|
||||
ccflags-$(CONFIG_SCSC_WLAN_OFFLINE_DATA_PLANE_PROFILE_TRACE) += -DCONFIG_SCSC_WLAN_OFFLINE_DATA_PLANE_PROFILE_TRACE
|
||||
ccflags-$(CONFIG_SCSC_WLAN_OFFLINE_TX_TRACE) += -DCONFIG_SCSC_WLAN_OFFLINE_TX_TRACE
|
||||
ccflags-$(CONFIG_SCSC_WLAN_HIP_CLEAR_TH_SLOT_SUPPORT) += -DCONFIG_SCSC_WLAN_HIP_CLEAR_TH_SLOT_SUPPORT
|
||||
ccflags-$(CONFIG_SCSC_WLAN_HIP_DEFER_SLOT_SUPPORT) += -DCONFIG_SCSC_WLAN_HIP_DEFER_SLOT_SUPPORT
|
||||
ccflags-$(CONFIG_SCSC_WLAN_RX_NAPI) += -DCONFIG_SCSC_WLAN_RX_NAPI
|
||||
ccflags-$(CONFIG_SCSC_WLAN_RX_NAPI_GRO) += -DCONFIG_SCSC_WLAN_RX_NAPI_GRO
|
||||
ccflags-$(CONFIG_SCSC_WLAN_WES_NCHO) += -DCONFIG_SCSC_WLAN_WES_NCHO
|
||||
ccflags-$(CONFIG_SCSC_WLAN_MUTEX_DEBUG) += -DCONFIG_SCSC_WLAN_MUTEX_DEBUG
|
||||
|
||||
ccflags-y += -DCONFIG_SCSC_WLAN_MAX_INTERFACES=$(CONFIG_SCSC_WLAN_MAX_INTERFACES)
|
||||
|
||||
# Android specific build options
|
||||
ccflags-$(CONFIG_SCSC_WLAN_ANDROID) += -DCONFIG_SCSC_WLAN_ANDROID
|
||||
|
||||
# enable Oxygen
|
||||
ifeq ($(CONFIG_SCSC_WLAN_OXYGEN_ENABLE),y)
|
||||
ccflags-y += -DCONFIG_SCSC_WLAN_OXYGEN_ENABLE
|
||||
ccflags-y += -DCONFIG_SCSC_WLAN_OXYGEN_UT_EXCEPTION
|
||||
endif
|
||||
|
||||
ccflags-y += -I$(src) -I$(src)/..
|
||||
ccflags-y += -I$(src)/../../../../../include -I$(src)/../../../../../include/scsc
|
||||
|
||||
ccflags-y += -DSLSI_TEST_DEV
|
||||
ccflags-y += $(CONFIG_SCSC_WLAN_EXTRA)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# module
|
||||
# ----------------------------------------------------------------------------
|
||||
obj-$(CONFIG_SCSC_WLAN_UNITTEST) := $(CONFIG_SCSC_WLAN_MODULE).o
|
||||
511
drivers/net/wireless/scsc/test/dev_test.c
Normal file
511
drivers/net/wireless/scsc/test/dev_test.c
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <net/ip.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "utils.h"
|
||||
#include "udi.h"
|
||||
#include "unittest.h"
|
||||
#include "mgt.h"
|
||||
#include "scsc/scsc_mx.h"
|
||||
|
||||
#define SLSI_TESTDRV_NAME "s5n2560_test"
|
||||
|
||||
static int radios = 11;
|
||||
module_param(radios, int, 0444);
|
||||
MODULE_PARM_DESC(radios, "Number of simulated radios");
|
||||
|
||||
/* spinlock for retaining the (struct slsi_dev) information */
|
||||
static struct slsi_spinlock slsi_test_devices_lock;
|
||||
static struct slsi_test_dev *slsi_test_devices[SLSI_UDI_MINOR_NODES];
|
||||
|
||||
static struct class *test_dev_class;
|
||||
/* Major number of device created by system. */
|
||||
static dev_t major_number;
|
||||
|
||||
static struct device_driver slsi_test_driver = {
|
||||
.name = SLSI_TESTDRV_NAME
|
||||
};
|
||||
|
||||
static void slsi_test_dev_attach_work(struct work_struct *work);
|
||||
static void slsi_test_dev_detach_work(struct work_struct *work);
|
||||
|
||||
static void slsi_test_dev_free(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SLSI_UDI_MINOR_NODES; i++) {
|
||||
struct slsi_test_dev *uftestdev;
|
||||
|
||||
slsi_spinlock_lock(&slsi_test_devices_lock);
|
||||
uftestdev = slsi_test_devices[i];
|
||||
slsi_test_devices[i] = NULL;
|
||||
slsi_spinlock_unlock(&slsi_test_devices_lock);
|
||||
if (uftestdev != NULL) {
|
||||
SLSI_INFO_NODEV("Free Test Device: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
uftestdev->hw_addr[0],
|
||||
uftestdev->hw_addr[1],
|
||||
uftestdev->hw_addr[2],
|
||||
uftestdev->hw_addr[3],
|
||||
uftestdev->hw_addr[4],
|
||||
uftestdev->hw_addr[5]);
|
||||
|
||||
if (WARN_ON(uftestdev->attached)) {
|
||||
slsi_test_bh_deinit(uftestdev);
|
||||
flush_workqueue(uftestdev->attach_detach_work_queue);
|
||||
}
|
||||
destroy_workqueue(uftestdev->attach_detach_work_queue);
|
||||
|
||||
slsi_test_udi_node_deinit(uftestdev);
|
||||
|
||||
device_unregister(uftestdev->dev);
|
||||
device_destroy(test_dev_class, uftestdev->dev->devt);
|
||||
}
|
||||
}
|
||||
|
||||
slsi_test_udi_deinit();
|
||||
|
||||
if (test_dev_class != NULL)
|
||||
class_destroy(test_dev_class);
|
||||
|
||||
unregister_chrdev_region(major_number, SLSI_UDI_MINOR_NODES);
|
||||
}
|
||||
|
||||
int slsi_sdio_func_drv_register(void)
|
||||
{
|
||||
int i = 0, err = 0, ret = 0;
|
||||
struct slsi_test_dev *uftestdev;
|
||||
dev_t devno;
|
||||
|
||||
SLSI_INFO_NODEV("Loading SLSI " SLSI_TESTDRV_NAME " Test Driver for mac80211\n");
|
||||
|
||||
if (radios > SLSI_UDI_MINOR_NODES) {
|
||||
SLSI_ERR_NODEV("Loading failed, configure SLSI_UDI_MINOR_NODES to match no. of simulated radios\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
slsi_spinlock_create(&slsi_test_devices_lock);
|
||||
memset(slsi_test_devices, 0x00, sizeof(slsi_test_devices));
|
||||
|
||||
/* Allocate two device numbers for each device. */
|
||||
ret = alloc_chrdev_region(&major_number, 0, SLSI_UDI_MINOR_NODES, SLSI_TESTDRV_NAME);
|
||||
if (ret) {
|
||||
SLSI_ERR_NODEV("Failed to add alloc dev numbers: %d\n", ret);
|
||||
unregister_chrdev_region(major_number, SLSI_UDI_MINOR_NODES);
|
||||
major_number = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
test_dev_class = class_create(THIS_MODULE, SLSI_TESTDRV_NAME);
|
||||
if (IS_ERR(test_dev_class))
|
||||
return -EAGAIN;
|
||||
|
||||
slsi_test_udi_init();
|
||||
|
||||
for (i = 0; i < radios; i++) {
|
||||
uftestdev = kmalloc(sizeof(*uftestdev), GFP_KERNEL);
|
||||
memset(uftestdev, 0, sizeof(*uftestdev));
|
||||
uftestdev->attach_detach_work_queue = alloc_ordered_workqueue("Test Work", 0);
|
||||
INIT_WORK(&uftestdev->attach_work, slsi_test_dev_attach_work);
|
||||
INIT_WORK(&uftestdev->detach_work, slsi_test_dev_detach_work);
|
||||
|
||||
devno = MKDEV(MAJOR(major_number), i);
|
||||
|
||||
uftestdev->dev = device_create(test_dev_class, NULL, devno, uftestdev, SLSI_TESTDRV_NAME "_dev%d", i);
|
||||
if (IS_ERR(uftestdev->dev)) {
|
||||
SLSI_ERR_NODEV("device_create FAILED, returned - (%ld)\n", PTR_ERR(uftestdev->dev));
|
||||
err = -ENOMEM;
|
||||
goto failed_free_all;
|
||||
}
|
||||
|
||||
uftestdev->dev->driver = &slsi_test_driver;
|
||||
|
||||
mutex_init(&uftestdev->attach_detach_mutex);
|
||||
slsi_test_bh_init(uftestdev);
|
||||
spin_lock_init(&uftestdev->route_spinlock);
|
||||
|
||||
if (slsi_test_udi_node_init(uftestdev, uftestdev->dev) != 0) {
|
||||
SLSI_ERR_NODEV("udi <node> init FAILED\n");
|
||||
goto failed_dev_unregister;
|
||||
}
|
||||
|
||||
/* Using a fixed MAC address instead of slsi_get_hw_mac_address(),
|
||||
* MAC Address format 00:12:FB:00:00:<xx> where xx increments for every PHY
|
||||
* (00:12:FB OUI Samsung Electronics)
|
||||
*/
|
||||
|
||||
memset(uftestdev->hw_addr, 0, sizeof(uftestdev->hw_addr));
|
||||
uftestdev->hw_addr[1] = 0x12;
|
||||
uftestdev->hw_addr[2] = 0xFB;
|
||||
/*To randomize the mac address*/
|
||||
uftestdev->hw_addr[ETH_ALEN - 1] += (i & (0xff));
|
||||
|
||||
SLSI_INFO_NODEV("Create Test Device: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
uftestdev->hw_addr[0],
|
||||
uftestdev->hw_addr[1],
|
||||
uftestdev->hw_addr[2],
|
||||
uftestdev->hw_addr[3],
|
||||
uftestdev->hw_addr[4],
|
||||
uftestdev->hw_addr[5]);
|
||||
slsi_test_devices[uftestdev->device_minor_number] = uftestdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed_dev_unregister:
|
||||
device_unregister(uftestdev->dev);
|
||||
device_destroy(test_dev_class, uftestdev->dev->devt);
|
||||
failed_free_all:
|
||||
slsi_test_dev_free();
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
void slsi_sdio_func_drv_unregister(void)
|
||||
{
|
||||
SLSI_INFO_NODEV("Unloading UF6K Test Driver for mac80211\n");
|
||||
slsi_test_dev_free();
|
||||
}
|
||||
|
||||
void slsi_test_dev_attach(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
struct slsi_dev *sdev;
|
||||
struct scsc_service_client service_client;
|
||||
|
||||
mutex_lock(&uftestdev->attach_detach_mutex);
|
||||
SLSI_INFO_NODEV("UnitTest UDI Attached : %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
uftestdev->hw_addr[0],
|
||||
uftestdev->hw_addr[1],
|
||||
uftestdev->hw_addr[2],
|
||||
uftestdev->hw_addr[3],
|
||||
uftestdev->hw_addr[4],
|
||||
uftestdev->hw_addr[5]);
|
||||
|
||||
if (uftestdev->attached) {
|
||||
SLSI_ERR_NODEV("attached == true\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
uftestdev->attached = true;
|
||||
sdev = slsi_dev_attach(uftestdev->dev, (struct scsc_mx *)uftestdev, &service_client);
|
||||
|
||||
slsi_spinlock_lock(&slsi_test_devices_lock);
|
||||
uftestdev->sdev = sdev;
|
||||
if (!sdev) {
|
||||
SLSI_ERR_NODEV("slsi_dev_attach() Failed\n");
|
||||
uftestdev->attached = false;
|
||||
} else {
|
||||
slsi_test_bh_start(uftestdev);
|
||||
}
|
||||
|
||||
slsi_spinlock_unlock(&slsi_test_devices_lock);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&uftestdev->attach_detach_mutex);
|
||||
}
|
||||
|
||||
void slsi_test_dev_detach(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
mutex_lock(&uftestdev->attach_detach_mutex);
|
||||
SLSI_INFO(uftestdev->sdev, "UnitTest UDI Detached : %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
uftestdev->hw_addr[0],
|
||||
uftestdev->hw_addr[1],
|
||||
uftestdev->hw_addr[2],
|
||||
uftestdev->hw_addr[3],
|
||||
uftestdev->hw_addr[4],
|
||||
uftestdev->hw_addr[5]);
|
||||
if (!uftestdev->attached) {
|
||||
SLSI_ERR(uftestdev->sdev, "attached != true\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
uftestdev->attached = false;
|
||||
if (uftestdev->sdev) {
|
||||
struct slsi_dev *sdev = uftestdev->sdev;
|
||||
|
||||
slsi_test_bh_stop(uftestdev);
|
||||
|
||||
slsi_dev_detach(sdev);
|
||||
slsi_spinlock_lock(&slsi_test_devices_lock);
|
||||
uftestdev->sdev = NULL;
|
||||
slsi_spinlock_unlock(&slsi_test_devices_lock);
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&uftestdev->attach_detach_mutex);
|
||||
}
|
||||
|
||||
void slsi_init_netdev_mac_addr(struct slsi_dev *sdev)
|
||||
{
|
||||
/* Get mac address from file system. */
|
||||
slsi_get_hw_mac_address(sdev, sdev->hw_addr);
|
||||
|
||||
SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_WLAN], sdev->hw_addr);
|
||||
|
||||
SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_P2P], sdev->hw_addr);
|
||||
sdev->netdev_addresses[SLSI_NET_INDEX_P2P][0] |= 0x02; /* Set the local bit */
|
||||
|
||||
SLSI_ETHER_COPY(sdev->netdev_addresses[SLSI_NET_INDEX_P2PX], sdev->hw_addr);
|
||||
sdev->netdev_addresses[SLSI_NET_INDEX_P2PX][0] |= 0x02; /* Set the local bit */
|
||||
sdev->netdev_addresses[SLSI_NET_INDEX_P2PX][4] ^= 0x80; /* EXOR 5th byte with 0x80 */
|
||||
|
||||
SLSI_ETHER_COPY(sdev->netdev[SLSI_NET_INDEX_WLAN]->dev_addr, sdev->netdev_addresses[SLSI_NET_INDEX_WLAN]);
|
||||
SLSI_ETHER_COPY(sdev->netdev[SLSI_NET_INDEX_P2P]->dev_addr, sdev->netdev_addresses[SLSI_NET_INDEX_P2P]);
|
||||
}
|
||||
|
||||
bool slsi_test_process_signal_ip_remap(struct slsi_test_dev *uftestdev, struct sk_buff *skb, struct slsi_test_data_route *route)
|
||||
{
|
||||
int proto = ntohs(skb->protocol);
|
||||
u8 *frame = fapi_get_data(skb) + 14;
|
||||
|
||||
switch (proto) {
|
||||
case 0x0806:
|
||||
{
|
||||
/* Arp */
|
||||
u8 *sha = &frame[8];
|
||||
u8 *spa = &frame[14];
|
||||
u8 *tha = &frame[18];
|
||||
u8 *tpa = &frame[24];
|
||||
|
||||
SLSI_UNUSED_PARAMETER(sha);
|
||||
SLSI_UNUSED_PARAMETER(spa);
|
||||
SLSI_UNUSED_PARAMETER(tha);
|
||||
SLSI_UNUSED_PARAMETER(tpa);
|
||||
|
||||
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "ARP: sha:%pM, spa:%d.%d.%d.%d, tha:%pM, tpa:%d.%d.%d.%d\n",
|
||||
sha, spa[0], spa[1], spa[2], spa[3],
|
||||
tha, tpa[0], tpa[1], tpa[2], tpa[3]);
|
||||
spa[2] = route->ipsubnet;
|
||||
tpa[2] = route->ipsubnet;
|
||||
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "ARP: sha:%pM, spa:%d.%d.%d.%d, tha:%pM, tpa:%d.%d.%d.%d\n",
|
||||
sha, spa[0], spa[1], spa[2], spa[3],
|
||||
tha, tpa[0], tpa[1], tpa[2], tpa[3]);
|
||||
return true;
|
||||
}
|
||||
case 0x0800:
|
||||
{
|
||||
/* IPv4 */
|
||||
struct iphdr *iph = (struct iphdr *)frame;
|
||||
u8 *src = (u8 *)&iph->saddr;
|
||||
u8 *dst = (u8 *)&iph->daddr;
|
||||
|
||||
SLSI_UNUSED_PARAMETER(src);
|
||||
SLSI_UNUSED_PARAMETER(dst);
|
||||
|
||||
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "PING: src:%d.%d.%d.%d, dst:%d.%d.%d.%d, check:0x%.4X\n",
|
||||
src[0], src[1], src[2], src[3],
|
||||
dst[0], dst[1], dst[2], dst[3],
|
||||
iph->check);
|
||||
src[2] = route->ipsubnet;
|
||||
dst[2] = route->ipsubnet;
|
||||
|
||||
/* Calculation of IP header checksum */
|
||||
iph->check = 0;
|
||||
ip_send_check(iph);
|
||||
|
||||
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "PING: src:%d.%d.%d.%d, dst:%d.%d.%d.%d, check:0x%.4X\n",
|
||||
src[0], src[1], src[2], src[3],
|
||||
dst[0], dst[1], dst[2], dst[3],
|
||||
iph->check);
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
SLSI_DBG4(uftestdev->sdev, SLSI_TEST, "Proto:0x%.4X\n", proto);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct slsi_test_data_route *slsi_test_process_signal_get_route(struct slsi_test_dev *uftestdev, const u8 *mac)
|
||||
{
|
||||
struct slsi_test_data_route *route;
|
||||
int i;
|
||||
|
||||
if (WARN_ON(!spin_is_locked(&uftestdev->route_spinlock)))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < SLSI_AP_PEER_CONNECTIONS_MAX; i++) {
|
||||
route = &uftestdev->route[i];
|
||||
if (route->configured && ether_addr_equal(route->mac, mac))
|
||||
return route;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct slsi_test_data_route *slsi_test_process_signal_get_free_route(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
struct slsi_test_data_route *route;
|
||||
int i;
|
||||
|
||||
if (WARN_ON(!spin_is_locked(&uftestdev->route_spinlock)))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < SLSI_AP_PEER_CONNECTIONS_MAX; i++) {
|
||||
route = &uftestdev->route[i];
|
||||
if (!route->configured)
|
||||
return route;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void slsi_test_process_signal_set_route(struct slsi_test_dev *uftestdev, struct sk_buff *skb)
|
||||
{
|
||||
struct slsi_test_data_route *route;
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 dest_device_minor_number = 0xFFFF;
|
||||
int i;
|
||||
|
||||
mac[0] = fapi_get_buff(skb, u.debug_generic_req.debug_words[2]) >> 8;
|
||||
mac[1] = fapi_get_buff(skb, u.debug_generic_req.debug_words[2]) & 0xFF;
|
||||
mac[2] = fapi_get_buff(skb, u.debug_generic_req.debug_words[3]) >> 8;
|
||||
mac[3] = fapi_get_buff(skb, u.debug_generic_req.debug_words[3]) & 0xFF;
|
||||
mac[4] = fapi_get_buff(skb, u.debug_generic_req.debug_words[4]) >> 8;
|
||||
mac[5] = fapi_get_buff(skb, u.debug_generic_req.debug_words[4]) & 0xFF;
|
||||
|
||||
slsi_spinlock_lock(&slsi_test_devices_lock);
|
||||
for (i = 0; i < SLSI_UDI_MINOR_NODES; i++) {
|
||||
struct slsi_test_dev *destdev = slsi_test_devices[i];
|
||||
|
||||
if (destdev != NULL && ether_addr_equal(destdev->hw_addr, mac))
|
||||
dest_device_minor_number = destdev->device_minor_number;
|
||||
}
|
||||
slsi_spinlock_unlock(&slsi_test_devices_lock);
|
||||
|
||||
if (dest_device_minor_number == 0xFFFF) {
|
||||
SLSI_ERR(uftestdev->sdev, "Setting Route for %pM FAILED. No match found\n", mac);
|
||||
return;
|
||||
}
|
||||
spin_lock(&uftestdev->route_spinlock);
|
||||
route = slsi_test_process_signal_get_route(uftestdev, mac);
|
||||
if (!route)
|
||||
route = slsi_test_process_signal_get_free_route(uftestdev);
|
||||
|
||||
if (route) {
|
||||
SLSI_DBG1(uftestdev->sdev, SLSI_TEST, "Setting Route for %pM -> %pM\n", uftestdev->hw_addr, mac);
|
||||
route->configured = true;
|
||||
route->test_device_minor_number = dest_device_minor_number;
|
||||
SLSI_ETHER_COPY(route->mac, mac);
|
||||
route->vif = fapi_get_u16(skb, u.debug_generic_req.debug_words[5]);
|
||||
route->ipsubnet = fapi_get_u16(skb, u.debug_generic_req.debug_words[6]) & 0xFF;
|
||||
route->sequence_number = 1;
|
||||
} else {
|
||||
SLSI_ERR(uftestdev->sdev, "Setting Route for %pM FAILED. No Free Route Entry\n", mac);
|
||||
}
|
||||
|
||||
spin_unlock(&uftestdev->route_spinlock);
|
||||
}
|
||||
|
||||
void slsi_test_process_signal_clear_route(struct slsi_test_dev *uftestdev, struct sk_buff *skb)
|
||||
{
|
||||
struct slsi_test_data_route *route;
|
||||
u8 mac[ETH_ALEN];
|
||||
|
||||
mac[0] = fapi_get_buff(skb, u.debug_generic_req.debug_words[2]) >> 8;
|
||||
mac[1] = fapi_get_buff(skb, u.debug_generic_req.debug_words[2]) & 0xFF;
|
||||
mac[2] = fapi_get_buff(skb, u.debug_generic_req.debug_words[3]) >> 8;
|
||||
mac[3] = fapi_get_buff(skb, u.debug_generic_req.debug_words[3]) & 0xFF;
|
||||
mac[4] = fapi_get_buff(skb, u.debug_generic_req.debug_words[4]) >> 8;
|
||||
mac[5] = fapi_get_buff(skb, u.debug_generic_req.debug_words[4]) & 0xFF;
|
||||
|
||||
spin_lock(&uftestdev->route_spinlock);
|
||||
SLSI_DBG1(uftestdev->sdev, SLSI_TEST, "Clearing Route for %pM\n", mac);
|
||||
route = slsi_test_process_signal_get_route(uftestdev, mac);
|
||||
if (route)
|
||||
route->configured = false;
|
||||
else
|
||||
SLSI_ERR(uftestdev->sdev, "Clearing Route for %pM FAILED. No Route Entry Found\n", mac);
|
||||
spin_unlock(&uftestdev->route_spinlock);
|
||||
}
|
||||
|
||||
bool slsi_test_process_signal(struct slsi_test_dev *uftestdev, struct sk_buff *skb)
|
||||
{
|
||||
if (fapi_get_sigid(skb) == DEBUG_GENERIC_REQ) {
|
||||
SLSI_DBG1(uftestdev->sdev, SLSI_TEST, "fapi_get_u16(skb, u.debug_generic_req.debug_words[0]) = %d\n", fapi_get_u16(skb, u.debug_generic_req.debug_words[0]));
|
||||
SLSI_DBG1(uftestdev->sdev, SLSI_TEST, "fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) = %d\n", fapi_get_u16(skb, u.debug_generic_req.debug_words[1]));
|
||||
if (fapi_get_u16(skb, u.debug_generic_req.debug_words[0]) == 0x1357) {
|
||||
if (fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) == 0)
|
||||
queue_work(uftestdev->attach_detach_work_queue, &uftestdev->detach_work);
|
||||
else if (fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) == 1)
|
||||
queue_work(uftestdev->attach_detach_work_queue, &uftestdev->attach_work);
|
||||
else if (fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) == 2)
|
||||
slsi_test_process_signal_set_route(uftestdev, skb);
|
||||
else if (fapi_get_u16(skb, u.debug_generic_req.debug_words[1]) == 3)
|
||||
slsi_test_process_signal_clear_route(uftestdev, skb);
|
||||
}
|
||||
slsi_kfree_skb(skb);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Automatically route the packet to the other test device and bypass the */
|
||||
if (fapi_get_sigid(skb) == MA_UNITDATA_REQ) {
|
||||
struct slsi_test_data_route *route;
|
||||
struct ethhdr *ehdr = (struct ethhdr *)skb->data;
|
||||
|
||||
spin_lock(&uftestdev->route_spinlock);
|
||||
route = slsi_test_process_signal_get_route(uftestdev, ehdr->h_dest);
|
||||
if (route && slsi_test_process_signal_ip_remap(uftestdev, skb, route)) {
|
||||
struct slsi_skb_cb *cb;
|
||||
struct fapi_signal req = *((struct fapi_signal *)skb->data);
|
||||
struct fapi_signal *ind;
|
||||
|
||||
/* Convert the MA_UNITDATA_REQ to a MA_UNITDATA_IND */
|
||||
WARN_ON(!skb_pull(skb, fapi_sig_size(ma_unitdata_req)));
|
||||
ind = (struct fapi_signal *)skb_push(skb, fapi_sig_size(ma_unitdata_ind));
|
||||
if (WARN_ON(!ind)) {
|
||||
slsi_kfree_skb(skb);
|
||||
spin_unlock(&uftestdev->route_spinlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
ind->id = cpu_to_le16(MA_UNITDATA_IND);
|
||||
ind->receiver_pid = 0;
|
||||
ind->sender_pid = 0;
|
||||
fapi_set_u16(skb, u.ma_unitdata_ind.vif, cpu_to_le16(route->vif));
|
||||
fapi_set_u16(skb, u.ma_unitdata_ind.sequence_number, route->sequence_number++);
|
||||
|
||||
cb = slsi_skb_cb_init(skb);
|
||||
cb->sig_length = fapi_get_expected_size(skb);
|
||||
cb->data_length = skb->len;
|
||||
|
||||
slsi_spinlock_lock(&slsi_test_devices_lock);
|
||||
if (slsi_test_devices[route->test_device_minor_number] &&
|
||||
slsi_test_devices[route->test_device_minor_number]->sdev) {
|
||||
if (slsi_hip_rx(slsi_test_devices[route->test_device_minor_number]->sdev, skb) != 0)
|
||||
slsi_kfree_skb(skb);
|
||||
} else {
|
||||
route->configured = false;
|
||||
slsi_kfree_skb(skb);
|
||||
}
|
||||
slsi_spinlock_unlock(&slsi_test_devices_lock);
|
||||
spin_unlock(&uftestdev->route_spinlock);
|
||||
return true;
|
||||
}
|
||||
spin_unlock(&uftestdev->route_spinlock);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void slsi_test_dev_attach_work(struct work_struct *work)
|
||||
{
|
||||
struct slsi_test_dev *uftestdev = container_of(work, struct slsi_test_dev, attach_work);
|
||||
|
||||
SLSI_INFO_NODEV("UnitTest TEST Attach\n");
|
||||
slsi_test_dev_attach(uftestdev);
|
||||
slsi_test_udi_node_reregister(uftestdev);
|
||||
}
|
||||
|
||||
static void slsi_test_dev_detach_work(struct work_struct *work)
|
||||
{
|
||||
struct slsi_test_dev *uftestdev = container_of(work, struct slsi_test_dev, detach_work);
|
||||
|
||||
SLSI_INFO(uftestdev->sdev, "UnitTest TEST Detach\n");
|
||||
slsi_test_dev_detach(uftestdev);
|
||||
}
|
||||
272
drivers/net/wireless/scsc/test/hip_test.c
Executable file
272
drivers/net/wireless/scsc/test/hip_test.c
Executable file
|
|
@ -0,0 +1,272 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include "unittest.h"
|
||||
#include "hip.h"
|
||||
#include "sap.h"
|
||||
#include "debug.h"
|
||||
#include "procfs.h"
|
||||
#include "hydra.h"
|
||||
#include "hip4.h"
|
||||
|
||||
#define SLSI_TEST_DEV_SDIO_BLOCK_SIZE 500
|
||||
bool hip4_sampler_sample_start_stop_q = true;
|
||||
struct hip4_hip_control test_hip_control;
|
||||
|
||||
/* SAP implementations container. Local and static to hip */
|
||||
static struct hip_sap {
|
||||
struct sap_api *sap[SAP_TOTAL];
|
||||
} hip_sap_cont;
|
||||
|
||||
/* Register SAP with HIP layer */
|
||||
int slsi_hip_sap_register(struct sap_api *sap_api)
|
||||
{
|
||||
u8 class = sap_api->sap_class;
|
||||
|
||||
if (class >= SAP_TOTAL)
|
||||
return -ENODEV;
|
||||
|
||||
hip_sap_cont.sap[class] = sap_api;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* UNregister SAP with HIP layer */
|
||||
int slsi_hip_sap_unregister(struct sap_api *sap_api)
|
||||
{
|
||||
u8 class = sap_api->sap_class;
|
||||
|
||||
if (class >= SAP_TOTAL)
|
||||
return -ENODEV;
|
||||
|
||||
hip_sap_cont.sap[class] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int slsi_hip_sap_setup(struct slsi_dev *sdev)
|
||||
{
|
||||
/* Execute callbacks to intorm Supported version */
|
||||
u16 version = 0;
|
||||
|
||||
if (hip_sap_cont.sap[SAP_MLME]->sap_version_supported) {
|
||||
version = scsc_wifi_get_hip_config_version_4_u16(&sdev->hip4_inst.hip_control->config_v4, sap_mlme_ver);
|
||||
if (hip_sap_cont.sap[SAP_MLME]->sap_version_supported(version))
|
||||
return -ENODEV;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (hip_sap_cont.sap[SAP_MA]->sap_version_supported) {
|
||||
version = scsc_wifi_get_hip_config_version_4_u16(&sdev->hip4_inst.hip_control->config_v4, sap_ma_ver);
|
||||
if (hip_sap_cont.sap[SAP_MA]->sap_version_supported(version))
|
||||
return -ENODEV;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (hip_sap_cont.sap[SAP_DBG]->sap_version_supported) {
|
||||
version = scsc_wifi_get_hip_config_version_4_u16(&sdev->hip4_inst.hip_control->config_v4, sap_debug_ver);
|
||||
if (hip_sap_cont.sap[SAP_DBG]->sap_version_supported(version))
|
||||
return -ENODEV;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (hip_sap_cont.sap[SAP_TST]->sap_version_supported) {
|
||||
version = scsc_wifi_get_hip_config_version_4_u16(&sdev->hip4_inst.hip_control->config_v4, sap_test_ver);
|
||||
if (hip_sap_cont.sap[SAP_TST]->sap_version_supported(version))
|
||||
return -ENODEV;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SAP rx proxy */
|
||||
int slsi_hip_rx(struct slsi_dev *sdev, struct sk_buff *skb)
|
||||
{
|
||||
u16 pid;
|
||||
|
||||
/* Udi test : If pid in UDI range then pass to UDI and ignore */
|
||||
slsi_log_clients_log_signal_fast(sdev, &sdev->log_clients, skb, SLSI_LOG_DIRECTION_TO_HOST);
|
||||
pid = fapi_get_u16(skb, receiver_pid);
|
||||
if (pid >= SLSI_TX_PROCESS_ID_UDI_MIN && pid <= SLSI_TX_PROCESS_ID_UDI_MAX) {
|
||||
slsi_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fapi_is_ma(skb))
|
||||
return hip_sap_cont.sap[SAP_MA]->sap_handler(sdev, skb);
|
||||
|
||||
if (fapi_is_mlme(skb))
|
||||
return hip_sap_cont.sap[SAP_MLME]->sap_handler(sdev, skb);
|
||||
|
||||
if (fapi_is_debug(skb))
|
||||
return hip_sap_cont.sap[SAP_DBG]->sap_handler(sdev, skb);
|
||||
|
||||
if (fapi_is_test(skb))
|
||||
return hip_sap_cont.sap[SAP_TST]->sap_handler(sdev, skb);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* value used at all levels in the driver */
|
||||
int slsi_hip_init(struct slsi_dev *sdev, struct device *dev)
|
||||
{
|
||||
SLSI_UNUSED_PARAMETER(dev);
|
||||
|
||||
memset(&sdev->hip, 0, sizeof(sdev->hip));
|
||||
|
||||
sdev->hip.sdev = sdev;
|
||||
mutex_init(&sdev->hip.hip_mutex);
|
||||
|
||||
sdev->hip4_inst.hip_control = &test_hip_control;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void slsi_hip_deinit(struct slsi_dev *sdev)
|
||||
{
|
||||
mutex_destroy(&sdev->hip.hip_mutex);
|
||||
}
|
||||
|
||||
int slsi_hip_stop(struct slsi_dev *sdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_transmit_frame(struct slsi_hip4 *hip, bool ctrl_packet, struct sk_buff *skb)
|
||||
{
|
||||
struct slsi_dev *sdev = container_of(hip, struct slsi_dev, hip4_inst);
|
||||
|
||||
slsi_log_clients_log_signal_fast(sdev, &sdev->log_clients, skb, SLSI_LOG_DIRECTION_FROM_HOST);
|
||||
|
||||
slsi_kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void slsi_test_bh_work_f(struct work_struct *work)
|
||||
{
|
||||
}
|
||||
|
||||
/* ALL Dummies to get UT build through goes below */
|
||||
bool hip4_sampler_sample_q;
|
||||
bool hip4_sampler_sample_qref;
|
||||
bool hip4_sampler_sample_int;
|
||||
bool hip4_sampler_sample_fapi;
|
||||
bool hip4_sampler_sample_through;
|
||||
bool hip4_sampler_sample_start_stop_q;
|
||||
bool hip4_sampler_sample_mbulk;
|
||||
bool hip4_sampler_sample_qfull;
|
||||
bool hip4_sampler_sample_mfull;
|
||||
bool hip4_sampler_vif;
|
||||
bool hip4_sampler_bot;
|
||||
bool hip4_sampler_pkt_tx;
|
||||
|
||||
void hip4_sampler_update_record(u32 minor, u8 param1, u8 param2, u8 param3, u8 param4)
|
||||
{
|
||||
}
|
||||
|
||||
void hip4_sampler_create(struct scsc_mx *mx)
|
||||
{
|
||||
}
|
||||
|
||||
void hip4_sampler_destroy(struct scsc_mx *mx)
|
||||
{
|
||||
}
|
||||
|
||||
int hip4_sampler_register_hip(struct scsc_mx *mx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_ctrl_q_init(struct scsc_wifi_fcq_ctrl_q *queue)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scsc_wifi_fcq_ctrl_q_deinit(struct scsc_wifi_fcq_ctrl_q *queue)
|
||||
{
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_unicast_qset_init(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, u8 qs_num, struct slsi_dev *sdev, u8 vif, struct slsi_peer *peer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_multicast_qset_init(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, struct slsi_dev *sdev, u8 vif)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scsc_wifi_fcq_qset_deinit(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, struct slsi_dev *sdev, u8 vif, struct slsi_peer *peer)
|
||||
{
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_transmit_data(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, u16 priority, struct slsi_dev *sdev, u8 vif, u8 peer_index)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_receive_data(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, u16 priority, struct slsi_dev *sdev, u8 vif, u8 peer_index)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_receive_data_no_peer(struct net_device *dev, u16 priority, struct slsi_dev *sdev, u8 vif, u8 peer_index)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scsc_wifi_fcq_pause_queues(struct slsi_dev *sdev)
|
||||
{
|
||||
}
|
||||
|
||||
void scsc_wifi_fcq_unpause_queues(struct slsi_dev *sdev)
|
||||
{
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_transmit_ctrl(struct net_device *dev, struct scsc_wifi_fcq_ctrl_q *queue)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_receive_ctrl(struct net_device *dev, struct scsc_wifi_fcq_ctrl_q *queue)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_update_smod(struct scsc_wifi_fcq_data_qset *qs, enum scsc_wifi_fcq_ps_state peer_ps_state,
|
||||
enum scsc_wifi_fcq_queue_set_type type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_8021x_port_state(struct net_device *dev, struct scsc_wifi_fcq_data_qset *qs, enum scsc_wifi_fcq_8021x_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_stat_queue(struct scsc_wifi_fcq_q_header *queue,
|
||||
struct scsc_wifi_fcq_q_stat *queue_stat,
|
||||
int *qmod, int *qcod)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsc_wifi_fcq_stat_queueset(struct scsc_wifi_fcq_data_qset *queue_set,
|
||||
struct scsc_wifi_fcq_q_stat *queue_stat,
|
||||
int *smod, int *scod, enum scsc_wifi_fcq_8021x_state *cp_state,
|
||||
u32 *peer_ps_state_transitions)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
84
drivers/net/wireless/scsc/test/hydra_test.c
Normal file
84
drivers/net/wireless/scsc/test/hydra_test.c
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "dev.h"
|
||||
#include "hydra.h"
|
||||
#include "unittest.h"
|
||||
#include "debug.h"
|
||||
#include "hip_bh.h"
|
||||
|
||||
int slsi_sm_service_driver_register(void)
|
||||
{
|
||||
int csr_result;
|
||||
|
||||
csr_result = slsi_sdio_func_drv_register();
|
||||
if (csr_result != 0) {
|
||||
SLSI_ERR_NODEV("Failed to register the pretend SDIO function driver: csrResult=%d\n", csr_result);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void slsi_sm_service_driver_unregister(void)
|
||||
{
|
||||
slsi_sdio_func_drv_unregister();
|
||||
}
|
||||
|
||||
void slsi_sm_service_failed(struct slsi_dev *sdev, const char *reason)
|
||||
{
|
||||
}
|
||||
|
||||
bool slsi_is_test_mode_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool slsi_is_232338_test_mode_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int check_mcd_232338_rf_mode(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int slsi_sm_wlan_service_start(struct slsi_dev *sdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void slsi_sm_wlan_service_stop(struct slsi_dev *sdev)
|
||||
{
|
||||
}
|
||||
|
||||
void slsi_hydra_get_chip_info(struct hydra_service_info *chip_info)
|
||||
{
|
||||
strcpy(chip_info->ver_str, "java - unittest");
|
||||
chip_info->hw_ver = 0xFFFF;
|
||||
chip_info->fw_rom_ver = 0xFFFFFFFF;
|
||||
chip_info->fw_patch_ver = 0xFFFFFFFF;
|
||||
chip_info->populated = true;
|
||||
}
|
||||
|
||||
int slsi_sm_wlan_service_open(struct slsi_dev *sdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mx140_file_request_conf(struct scsc_mx *mx, const struct firmware **conf, const char *config_rel_path)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mx140_file_release_conf(struct scsc_mx *mx, const struct firmware *conf)
|
||||
{
|
||||
}
|
||||
|
||||
void slsi_sm_wlan_service_close(struct slsi_dev *sdev)
|
||||
{
|
||||
}
|
||||
632
drivers/net/wireless/scsc/test/udi_test.c
Normal file
632
drivers/net/wireless/scsc/test/udi_test.c
Normal file
|
|
@ -0,0 +1,632 @@
|
|||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include "dev.h"
|
||||
|
||||
#include "hip.h"
|
||||
#include "log_clients.h"
|
||||
#include "debug.h"
|
||||
#include "unittest.h"
|
||||
#include "udi.h"
|
||||
|
||||
#include "unifiio.h"
|
||||
|
||||
#define UDI_CHAR_DEVICE_NAME "s5e7570unittesthip"
|
||||
#define UDI_CLASS_NAME "s5e7570unittesthip"
|
||||
|
||||
/**
|
||||
* Control character device for debug
|
||||
* ==================================
|
||||
*/
|
||||
#define NUM_CHAR_CLIENTS 1 /* Number of client programmes on one node. */
|
||||
|
||||
#define MAX_MINOR (SLSI_UDI_MINOR_NODES - 1) /* Maximum node number. */
|
||||
static dev_t major_number; /* Major number of device created by system. */
|
||||
static struct class *class; /* Device class. */
|
||||
|
||||
struct slsi_test_cdev_client;
|
||||
|
||||
struct slsi_cdev {
|
||||
int minor;
|
||||
struct cdev cdev;
|
||||
struct slsi_test_cdev_client *client[NUM_CHAR_CLIENTS];
|
||||
|
||||
struct slsi_test_dev *uftestdev;
|
||||
struct device *parent;
|
||||
};
|
||||
|
||||
struct slsi_test_cdev_client {
|
||||
struct slsi_cdev *ufcdev;
|
||||
int log_enabled;
|
||||
|
||||
/* Flags set for special filtering of ma_packet data */
|
||||
u16 ma_packet_filter_config;
|
||||
|
||||
struct sk_buff_head log_list;
|
||||
wait_queue_head_t log_wq;
|
||||
};
|
||||
|
||||
/**
|
||||
* One minor node per phy. In normal driver mode, this may be one.
|
||||
* In unit test mode, this may be several.
|
||||
*/
|
||||
static struct slsi_cdev *uf_cdevs[SLSI_UDI_MINOR_NODES];
|
||||
|
||||
static int udi_log_event(struct slsi_log_client *log_client, struct sk_buff *skb, int dir);
|
||||
static int send_signal_to_log_filter(struct slsi_log_client *log_client, struct sk_buff *skb, int dir);
|
||||
static int send_signal_to_inverse_log_filter(struct slsi_log_client *log_client, struct sk_buff *skb, int dir);
|
||||
|
||||
static int slsi_test_cdev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct slsi_cdev *uf_cdev;
|
||||
struct slsi_test_cdev_client *client;
|
||||
int indx;
|
||||
int minor;
|
||||
|
||||
minor = iminor(inode);
|
||||
if (minor > MAX_MINOR) {
|
||||
SLSI_ERR_NODEV("minor %d exceeds range\n", minor);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uf_cdev = uf_cdevs[minor];
|
||||
if (!uf_cdev) {
|
||||
SLSI_ERR_NODEV("no cdev instance for minor %d\n", minor);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!uf_cdev->uftestdev) {
|
||||
SLSI_ERR_NODEV("uftestdev not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (indx = 0; indx < NUM_CHAR_CLIENTS; indx++)
|
||||
if (uf_cdev->client[indx] == NULL)
|
||||
break;
|
||||
if (indx >= NUM_CHAR_CLIENTS) {
|
||||
SLSI_ERR_NODEV("already opened\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
client = kmalloc(sizeof(*client), GFP_KERNEL);
|
||||
if (client == NULL)
|
||||
return -ENOMEM;
|
||||
memset(client, 0, sizeof(struct slsi_test_cdev_client));
|
||||
|
||||
/* init other resource */
|
||||
skb_queue_head_init(&client->log_list);
|
||||
init_waitqueue_head(&client->log_wq);
|
||||
|
||||
client->ufcdev = uf_cdev;
|
||||
uf_cdev->client[indx] = client;
|
||||
file->private_data = client;
|
||||
|
||||
slsi_test_dev_attach(client->ufcdev->uftestdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slsi_test_cdev_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct slsi_test_cdev_client *client = (void *)filp->private_data;
|
||||
struct slsi_cdev *uf_cdev;
|
||||
int indx;
|
||||
int minor;
|
||||
|
||||
minor = iminor(inode);
|
||||
if (minor > MAX_MINOR) {
|
||||
SLSI_ERR_NODEV("minor %d exceeds range\n", minor);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uf_cdev = uf_cdevs[minor];
|
||||
if (!uf_cdev) {
|
||||
SLSI_ERR_NODEV("no cdev instance for minor %d\n", minor);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (client == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!client->ufcdev) {
|
||||
SLSI_ERR_NODEV("ufcdev not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!client->ufcdev->uftestdev) {
|
||||
SLSI_ERR_NODEV("uftestdev not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (indx = 0; indx < NUM_CHAR_CLIENTS; indx++)
|
||||
if (uf_cdev->client[indx] == client)
|
||||
break;
|
||||
if (indx >= NUM_CHAR_CLIENTS) {
|
||||
SLSI_ERR_NODEV("client not found in list\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (waitqueue_active(&client->log_wq))
|
||||
wake_up_interruptible(&client->log_wq);
|
||||
|
||||
if (client->log_enabled && client->ufcdev->uftestdev->sdev)
|
||||
slsi_log_client_unregister(client->ufcdev->uftestdev->sdev, client);
|
||||
|
||||
slsi_test_dev_detach(client->ufcdev->uftestdev);
|
||||
|
||||
slsi_skb_queue_purge(&client->log_list);
|
||||
|
||||
/* free other resource */
|
||||
kfree(client);
|
||||
|
||||
uf_cdev->client[indx] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t slsi_test_cdev_read(struct file *filp, char *p, size_t len, loff_t *poff)
|
||||
{
|
||||
struct slsi_test_cdev_client *client = (void *)filp->private_data;
|
||||
int msglen;
|
||||
struct sk_buff *skb;
|
||||
|
||||
SLSI_UNUSED_PARAMETER(poff);
|
||||
|
||||
if (client == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!skb_queue_len(&client->log_list)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return 0;
|
||||
|
||||
/* wait until getting a signal */
|
||||
if (wait_event_interruptible(client->log_wq, skb_queue_len(&client->log_list)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
skb = slsi_skb_dequeue(&client->log_list);
|
||||
|
||||
msglen = skb->len;
|
||||
if (msglen > (s32)len) {
|
||||
SLSI_WARN_NODEV("truncated read to %d actual msg len is %lu\n", msglen, (unsigned long int)len);
|
||||
msglen = len;
|
||||
}
|
||||
|
||||
SLSI_DBG_HEX_NODEV(SLSI_TEST, skb->data, skb->len, "cdev read skb:%p skb->data:%p\n", skb, skb->data);
|
||||
if (copy_to_user(p, skb->data, msglen)) {
|
||||
SLSI_ERR_NODEV("Failed to copy UDI log to user\n");
|
||||
slsi_kfree_skb(skb);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
slsi_kfree_skb(skb);
|
||||
return msglen;
|
||||
}
|
||||
|
||||
static ssize_t slsi_test_cdev_write(struct file *filp, const char *p, size_t len, loff_t *poff)
|
||||
{
|
||||
struct slsi_test_cdev_client *client;
|
||||
struct slsi_test_dev *uftestdev;
|
||||
struct sk_buff *skb;
|
||||
struct slsi_skb_cb *cb;
|
||||
u8 *data;
|
||||
|
||||
SLSI_UNUSED_PARAMETER(poff);
|
||||
|
||||
client = (void *)filp->private_data;
|
||||
if (client == NULL) {
|
||||
SLSI_ERR_NODEV("filep private data not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!client->ufcdev) {
|
||||
SLSI_ERR_NODEV("ufcdev not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uftestdev = client->ufcdev->uftestdev;
|
||||
if (!uftestdev) {
|
||||
SLSI_ERR_NODEV("uftestdev not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skb = slsi_alloc_skb(len, GFP_KERNEL);
|
||||
data = skb_put(skb, len);
|
||||
if (copy_from_user(data, p, len)) {
|
||||
SLSI_ERR_NODEV("copy from user failed\n");
|
||||
slsi_kfree_skb(skb);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (skb->len < sizeof(struct fapi_signal_header)) {
|
||||
SLSI_ERR_NODEV("Data(%d) too short for a signal\n", skb->len);
|
||||
slsi_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
SLSI_DBG_HEX_NODEV(SLSI_TEST, skb->data, skb->len, "cdev write skb:%p skb->data:%p\n", skb, skb->data);
|
||||
|
||||
/* Intercept some requests */
|
||||
if (slsi_test_process_signal(uftestdev, skb))
|
||||
return len;
|
||||
|
||||
{
|
||||
struct slsi_dev *sdev;
|
||||
|
||||
sdev = uftestdev->sdev;
|
||||
if (!sdev) {
|
||||
SLSI_ERR_NODEV("sdev not set\n");
|
||||
slsi_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cb = slsi_skb_cb_init(skb);
|
||||
cb->sig_length = fapi_get_expected_size(skb);
|
||||
cb->data_length = skb->len;
|
||||
|
||||
if (WARN_ON(slsi_hip_rx(sdev, skb))) {
|
||||
slsi_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static long slsi_test_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct slsi_test_cdev_client *client = (void *)filp->private_data;
|
||||
struct slsi_test_dev *uftestdev;
|
||||
struct slsi_dev *sdev;
|
||||
long r = 0;
|
||||
int int_param;
|
||||
|
||||
if (client == NULL || client->ufcdev == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
uftestdev = client->ufcdev->uftestdev;
|
||||
if (!uftestdev) {
|
||||
SLSI_ERR_NODEV("uftestdev not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sdev = uftestdev->sdev;
|
||||
if (!sdev) {
|
||||
SLSI_ERR_NODEV("sdev not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
FUNC_ENTER_NODEV();
|
||||
|
||||
slsi_wakelock(&sdev->wlan_wl);
|
||||
|
||||
switch (cmd) {
|
||||
case UNIFI_GET_UDI_ENABLE:
|
||||
int_param = client->log_enabled;
|
||||
put_user(int_param, (int *)arg);
|
||||
break;
|
||||
|
||||
case UNIFI_SET_UDI_ENABLE:
|
||||
if (get_user(int_param, (int *)arg)) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (int_param) {
|
||||
slsi_log_client_register(sdev, client, udi_log_event, NULL, 0, 0);
|
||||
client->log_enabled = 1;
|
||||
} else {
|
||||
slsi_log_client_unregister(sdev, client);
|
||||
client->log_enabled = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case UNIFI_SET_UDI_LOG_MASK:
|
||||
{
|
||||
struct unifiio_filter_t filter;
|
||||
int i;
|
||||
|
||||
/* to minimise load on data path, list is converted here to array indexed by signal number */
|
||||
if (copy_from_user(&filter, (void *)arg, sizeof(filter))) {
|
||||
SLSI_ERR(sdev, "UNIFI_SET_UDI_LOG_MASK: Failed to copy from userspace\n");
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (filter.signal_ids_n) {
|
||||
char *signal_filter_index;
|
||||
int max;
|
||||
int min;
|
||||
int size = filter.signal_ids_n * sizeof(filter.signal_ids[0]);
|
||||
u16 *signal_ids = kmalloc(size, GFP_KERNEL);
|
||||
|
||||
if (!signal_ids) {
|
||||
r = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
max = signal_ids[0];
|
||||
min = signal_ids[0];
|
||||
|
||||
if (copy_from_user(signal_ids, filter.signal_ids, size)) {
|
||||
SLSI_ERR(sdev, "UNIFI_SET_UDI_LOG_MASK: Failed to copy filter from userspace\n");
|
||||
kfree(signal_ids);
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
/* find maximum and minimum signal id in filter */
|
||||
for (i = 0; i < filter.signal_ids_n; i++) {
|
||||
if (signal_ids[i] & UDI_MA_UNITDATA_FILTER_ALLOW_MASK) {
|
||||
client->ma_packet_filter_config |= signal_ids[i];
|
||||
continue;
|
||||
}
|
||||
if (signal_ids[i] > max)
|
||||
max = signal_ids[i];
|
||||
else if (signal_ids[i] < min)
|
||||
min = signal_ids[i];
|
||||
}
|
||||
/* and create array only big enough to index the range of signal id specified */
|
||||
signal_filter_index = kmalloc(max - min + 1, GFP_KERNEL);
|
||||
if (signal_filter_index) {
|
||||
memset(signal_filter_index, 0, max - min + 1);
|
||||
for (i = 0; i < filter.signal_ids_n; i++) {
|
||||
if (signal_ids[i] & UDI_MA_UNITDATA_FILTER_ALLOW_MASK)
|
||||
continue;
|
||||
signal_filter_index[signal_ids[i] - min] = 1;
|
||||
}
|
||||
slsi_log_client_unregister(sdev, client);
|
||||
slsi_log_client_register(sdev, client,
|
||||
filter.log_listed_flag ? send_signal_to_inverse_log_filter :
|
||||
send_signal_to_log_filter, signal_filter_index, min, max);
|
||||
} else {
|
||||
r = -ENOMEM;
|
||||
}
|
||||
kfree(signal_ids);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SLSI_WARN(sdev, "Operation (%d) not supported\n", cmd);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
slsi_wakeunlock(&sdev->wlan_wl);
|
||||
return r;
|
||||
}
|
||||
|
||||
static unsigned int slsi_test_cdev_poll(struct file *filp, poll_table *wait)
|
||||
{
|
||||
struct slsi_test_cdev_client *client = (void *)filp->private_data;
|
||||
unsigned int mask = 0;
|
||||
int ready;
|
||||
|
||||
ready = skb_queue_len(&client->log_list);
|
||||
poll_wait(filp, &client->log_wq, wait);
|
||||
if (ready)
|
||||
mask |= POLLIN | POLLRDNORM; /* readable */
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* we know for sure that there is a filter present in log_client->signal_filter if this function is called.
|
||||
* we know this because it is called only through a function pointer that is assigned
|
||||
* only when a filter is also set up in the log_client
|
||||
*/
|
||||
static int send_signal_to_log_filter(struct slsi_log_client *log_client, struct sk_buff *skb, int dir)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 signal_id = fapi_get_u16(skb, id);
|
||||
|
||||
if (signal_id > log_client->max_signal_id || signal_id < log_client->min_signal_id || !log_client->signal_filter[signal_id - log_client->min_signal_id])
|
||||
ret = udi_log_event(log_client, skb, dir);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int send_signal_to_inverse_log_filter(struct slsi_log_client *log_client, struct sk_buff *skb, int dir)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 signal_id = fapi_get_u16(skb, id);
|
||||
|
||||
if (signal_id <= log_client->max_signal_id && signal_id >= log_client->min_signal_id && log_client->signal_filter[signal_id - log_client->min_signal_id])
|
||||
ret = udi_log_event(log_client, skb, dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int udi_log_event(struct slsi_log_client *log_client, struct sk_buff *skb, int dir)
|
||||
{
|
||||
struct slsi_test_cdev_client *client = log_client->log_client_ctx;
|
||||
struct udi_msg_t msg;
|
||||
struct udi_msg_t *msg_skb;
|
||||
|
||||
if (WARN_ON(client == NULL))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(skb == NULL))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(skb->len == 0))
|
||||
return -EINVAL;
|
||||
|
||||
skb = slsi_skb_copy_expand(skb, sizeof(msg), 0, GFP_ATOMIC);
|
||||
if (WARN_ON(!skb))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Intercept some requests */
|
||||
if (slsi_test_process_signal(client->ufcdev->uftestdev, skb))
|
||||
return -ECANCELED;
|
||||
|
||||
if (WARN_ON(skb_headroom(skb) < sizeof(msg)))
|
||||
return -ENOMEM;
|
||||
|
||||
msg.length = sizeof(msg) + skb->len;
|
||||
msg.timestamp = jiffies_to_msecs(jiffies);
|
||||
msg.direction = dir;
|
||||
msg.signal_length = fapi_get_siglen(skb);
|
||||
|
||||
msg_skb = (struct udi_msg_t *)skb_push(skb, sizeof(msg));
|
||||
*msg_skb = msg;
|
||||
|
||||
slsi_skb_queue_tail(&client->log_list, skb);
|
||||
|
||||
/* Wake any waiting user process */
|
||||
wake_up_interruptible(&client->log_wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \
|
||||
device_create(_class, _parent, _devno, _priv, _fmt, _args)
|
||||
|
||||
static const struct file_operations slsi_test_cdev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = slsi_test_cdev_open,
|
||||
.release = slsi_test_cdev_release,
|
||||
.read = slsi_test_cdev_read,
|
||||
.write = slsi_test_cdev_write,
|
||||
.unlocked_ioctl = slsi_test_cdev_ioctl,
|
||||
.compat_ioctl = slsi_test_cdev_ioctl,
|
||||
.poll = slsi_test_cdev_poll,
|
||||
};
|
||||
|
||||
#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \
|
||||
device_create(_class, _parent, _devno, _priv, _fmt, _args)
|
||||
|
||||
static int slsi_get_minor(void)
|
||||
{
|
||||
int minor;
|
||||
|
||||
for (minor = 0; minor < SLSI_UDI_MINOR_NODES; minor++)
|
||||
if (uf_cdevs[minor] == 0)
|
||||
return minor;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int slsi_test_cdev_create(struct slsi_test_dev *uftestdev, struct device *parent)
|
||||
{
|
||||
dev_t devno;
|
||||
int ret;
|
||||
struct slsi_cdev *pdev;
|
||||
int minor;
|
||||
|
||||
FUNC_ENTER_NODEV();
|
||||
minor = slsi_get_minor();
|
||||
if (minor < 0) {
|
||||
SLSI_ERR_NODEV("no minor numbers available\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pdev = kmalloc(sizeof(*pdev), GFP_KERNEL);
|
||||
if (pdev == NULL)
|
||||
return -ENOMEM;
|
||||
memset(pdev, 0, sizeof(*pdev));
|
||||
|
||||
cdev_init(&pdev->cdev, &slsi_test_cdev_fops);
|
||||
pdev->cdev.owner = THIS_MODULE;
|
||||
pdev->minor = minor;
|
||||
devno = MKDEV(MAJOR(major_number), minor);
|
||||
ret = cdev_add(&pdev->cdev, devno, 1);
|
||||
if (ret) {
|
||||
SLSI_ERR_NODEV("cdev_add failed with %d for minor %d\n", ret, minor);
|
||||
kfree(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pdev->uftestdev = uftestdev;
|
||||
pdev->parent = parent;
|
||||
if (!UF_DEVICE_CREATE(class, pdev->parent, devno, pdev, UDI_CHAR_DEVICE_NAME "%d", minor)) {
|
||||
cdev_del(&pdev->cdev);
|
||||
kfree(pdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
uftestdev->uf_cdev = (void *)pdev;
|
||||
uftestdev->device_minor_number = minor;
|
||||
uf_cdevs[minor] = pdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void slsi_test_cdev_destroy(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
struct slsi_cdev *pdev = (struct slsi_cdev *)uftestdev->uf_cdev;
|
||||
|
||||
FUNC_ENTER_NODEV();
|
||||
if (!pdev)
|
||||
return;
|
||||
device_destroy(class, pdev->cdev.dev);
|
||||
cdev_del(&pdev->cdev);
|
||||
uftestdev->uf_cdev = 0;
|
||||
uf_cdevs[pdev->minor] = 0;
|
||||
kfree(pdev);
|
||||
}
|
||||
|
||||
static int udi_initialised;
|
||||
|
||||
int slsi_test_udi_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
memset(uf_cdevs, 0, sizeof(uf_cdevs));
|
||||
|
||||
/* Allocate two device numbers for each device. */
|
||||
ret = alloc_chrdev_region(&major_number, 0, SLSI_UDI_MINOR_NODES, UDI_CLASS_NAME);
|
||||
if (ret) {
|
||||
SLSI_ERR_NODEV("Failed to add alloc dev numbers: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create a UniFi class */
|
||||
class = class_create(THIS_MODULE, UDI_CLASS_NAME);
|
||||
if (IS_ERR(class)) {
|
||||
SLSI_ERR_NODEV("Failed to create UniFi class\n");
|
||||
unregister_chrdev_region(major_number, SLSI_UDI_MINOR_NODES);
|
||||
major_number = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
udi_initialised = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int slsi_test_udi_deinit(void)
|
||||
{
|
||||
if (!udi_initialised)
|
||||
return -1;
|
||||
class_destroy(class);
|
||||
unregister_chrdev_region(major_number, SLSI_UDI_MINOR_NODES);
|
||||
udi_initialised = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int slsi_test_udi_node_init(struct slsi_test_dev *uftestdev, struct device *parent)
|
||||
{
|
||||
FUNC_ENTER_NODEV();
|
||||
if (!udi_initialised)
|
||||
return -1;
|
||||
return slsi_test_cdev_create(uftestdev, parent);
|
||||
}
|
||||
|
||||
int slsi_test_udi_node_reregister(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
struct slsi_cdev *pdev = uftestdev->uf_cdev;
|
||||
int indx;
|
||||
|
||||
if (uftestdev->sdev)
|
||||
for (indx = 0; indx < NUM_CHAR_CLIENTS; indx++)
|
||||
if (pdev->client[indx] != NULL && pdev->client[indx]->log_enabled)
|
||||
slsi_log_client_register(uftestdev->sdev, pdev->client[indx], udi_log_event, NULL, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int slsi_test_udi_node_deinit(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
FUNC_ENTER_NODEV();
|
||||
if (!udi_initialised)
|
||||
return -1;
|
||||
slsi_test_cdev_destroy(uftestdev);
|
||||
return 0;
|
||||
}
|
||||
129
drivers/net/wireless/scsc/test/unittest.h
Executable file
129
drivers/net/wireless/scsc/test/unittest.h
Executable file
|
|
@ -0,0 +1,129 @@
|
|||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __SLSI_UNITTEST_H__
|
||||
#define __SLSI_UNITTEST_H__
|
||||
|
||||
#include "dev.h"
|
||||
|
||||
struct slsi_test_dev;
|
||||
struct slsi_test_bh_work {
|
||||
bool available;
|
||||
struct slsi_test_dev *uftestdev;
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct work;
|
||||
struct slsi_spinlock spinlock;
|
||||
};
|
||||
|
||||
struct slsi_test_data_route {
|
||||
bool configured;
|
||||
u16 test_device_minor_number; /* index into slsi_test_devices[] */
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 vif;
|
||||
u8 ipsubnet;
|
||||
u16 sequence_number;
|
||||
};
|
||||
|
||||
struct slsi_test_dev {
|
||||
/* This is used for:
|
||||
* 1) The uf6kunittesthip<n> chardevice number
|
||||
* 2) The uf6kunittest<n> chardevice number
|
||||
* 3) The /procf/devices/unifi<n> number
|
||||
*/
|
||||
int device_minor_number;
|
||||
|
||||
void *uf_cdev;
|
||||
struct device *dev;
|
||||
struct slsi_dev *sdev;
|
||||
|
||||
struct workqueue_struct *attach_detach_work_queue;
|
||||
/* a std mutex */
|
||||
struct mutex attach_detach_mutex;
|
||||
struct work_struct attach_work;
|
||||
struct work_struct detach_work;
|
||||
bool attached;
|
||||
|
||||
u8 hw_addr[ETH_ALEN];
|
||||
struct slsi_test_bh_work bh_work;
|
||||
|
||||
/* a std spinlock */
|
||||
spinlock_t route_spinlock;
|
||||
struct slsi_test_data_route route[SLSI_AP_PEER_CONNECTIONS_MAX];
|
||||
};
|
||||
|
||||
void slsi_test_dev_attach(struct slsi_test_dev *uftestdev);
|
||||
void slsi_test_dev_detach(struct slsi_test_dev *uftestdev);
|
||||
bool slsi_test_process_signal(struct slsi_test_dev *uftestdev, struct sk_buff *skb);
|
||||
|
||||
int slsi_test_udi_node_init(struct slsi_test_dev *uftestdev, struct device *parent);
|
||||
int slsi_test_udi_node_reregister(struct slsi_test_dev *uftestdev);
|
||||
int slsi_test_udi_node_deinit(struct slsi_test_dev *uftestdev);
|
||||
|
||||
int slsi_test_udi_init(void);
|
||||
int slsi_test_udi_deinit(void);
|
||||
|
||||
void slsi_test_bh_work_f(struct work_struct *work);
|
||||
static inline int slsi_test_bh_init(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
uftestdev->bh_work.available = false;
|
||||
uftestdev->bh_work.uftestdev = uftestdev;
|
||||
slsi_spinlock_create(&uftestdev->bh_work.spinlock);
|
||||
INIT_WORK(&uftestdev->bh_work.work, slsi_test_bh_work_f);
|
||||
uftestdev->bh_work.workqueue = alloc_ordered_workqueue("slsi_wlan_unittest_bh", 0);
|
||||
if (!uftestdev->bh_work.workqueue)
|
||||
return -ENOMEM;
|
||||
uftestdev->bh_work.available = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void slsi_test_bh_start(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
|
||||
uftestdev->bh_work.available = true;
|
||||
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
|
||||
}
|
||||
|
||||
static inline void slsi_test_bh_run(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
|
||||
if (!uftestdev->bh_work.available)
|
||||
goto exit;
|
||||
queue_work(uftestdev->bh_work.workqueue, &uftestdev->bh_work.work);
|
||||
exit:
|
||||
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
|
||||
}
|
||||
|
||||
static inline void slsi_test_bh_stop(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
struct workqueue_struct *workqueue = NULL;
|
||||
|
||||
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
|
||||
uftestdev->bh_work.available = false;
|
||||
workqueue = uftestdev->bh_work.workqueue;
|
||||
uftestdev->bh_work.workqueue = NULL;
|
||||
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
|
||||
|
||||
if (workqueue)
|
||||
flush_workqueue(workqueue);
|
||||
}
|
||||
|
||||
static inline void slsi_test_bh_deinit(struct slsi_test_dev *uftestdev)
|
||||
{
|
||||
struct workqueue_struct *workqueue = NULL;
|
||||
|
||||
slsi_spinlock_lock(&uftestdev->bh_work.spinlock);
|
||||
WARN_ON(uftestdev->bh_work.available);
|
||||
uftestdev->bh_work.available = false;
|
||||
workqueue = uftestdev->bh_work.workqueue;
|
||||
uftestdev->bh_work.workqueue = NULL;
|
||||
slsi_spinlock_unlock(&uftestdev->bh_work.spinlock);
|
||||
if (workqueue) {
|
||||
flush_workqueue(workqueue);
|
||||
destroy_workqueue(workqueue);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue