Skip to content
Permalink
Browse files
wireless: Initial driver submission for pureLiFi STA devices
This introduces the pureLiFi LiFi driver for LiFi-X, LiFi-XC
and LiFi-XL USB devices.

This driver implementation has been based on the zd1211rw driver.

Driver is based on 802.11 softMAC Architecture and uses
native 802.11 for configuration and management

The driver is compiled and tested in ARM, x86 architectures and
compiled in powerpc architecture

Signed-off-by: Srinivasan Raju <srini.raju@purelifi.com>
  • Loading branch information
srini-purelifi authored and intel-lab-lkp committed Oct 14, 2020
1 parent df41c19 commit 2f1cd7604f364eba9428b88e2ab38c2a42272fcd
Show file tree
Hide file tree
Showing 12 changed files with 3,100 additions and 0 deletions.
@@ -14108,6 +14108,11 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/admin-guide/media/pulse8-cec.rst
F: drivers/media/cec/usb/pulse8/

PUREILIFI USB DRIVER
M: Srinivasan Raju <srini.raju@purelifi.com>
S: Maintained
F: drivers/net/wireless/purelifi

PVRUSB2 VIDEO4LINUX DRIVER
M: Mike Isely <isely@pobox.com>
L: pvrusb2@isely.net (subscribers-only)
@@ -48,6 +48,7 @@ source "drivers/net/wireless/st/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zydas/Kconfig"
source "drivers/net/wireless/quantenna/Kconfig"
source "drivers/net/wireless/purelifi/Kconfig"

config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"
@@ -20,6 +20,7 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/
obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
obj-$(CONFIG_WLAN_VENDOR_PURELIFI) += purelifi/

# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
@@ -0,0 +1,27 @@
# SPDX-License-Identifier: GPL-2.0
config WLAN_VENDOR_PURELIFI
bool "pureLiFi devices"
default y
help
If you have a pureLiFi device, say Y.

Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.

if WLAN_VENDOR_PURELIFI

config PURELIFI

tristate "pureLiFi device support"
depends on CFG80211 && MAC80211 && USB
help
This driver makes the adapter appear as a normal WLAN interface.

The pureLiFi device requires external STA firmware to be loaded.

To compile this driver as a module, choose M here: the module will
be called purelifi.

endif # WLAN_VENDOR_PURELIFI
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PURELIFI) := purelifi.o
purelifi-objs += chip.o usb.o mac.o
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0

#include <linux/kernel.h>
#include <linux/errno.h>

#include "chip.h"
#include "mac.h"
#include "usb.h"

void purelifi_chip_init(struct purelifi_chip *chip,
struct ieee80211_hw *hw,
struct usb_interface *intf)
{
memset(chip, 0, sizeof(*chip));
mutex_init(&chip->mutex);
purelifi_usb_init(&chip->usb, hw, intf);
}

void purelifi_chip_release(struct purelifi_chip *chip)
{
purelifi_usb_release(&chip->usb);
mutex_destroy(&chip->mutex);
}

int purelifi_set_beacon_interval(struct purelifi_chip *chip, u16 interval,
u8 dtim_period, int type)
{
if (!interval || (chip->beacon_set &&
chip->beacon_interval == interval)) {
return 0;
}

chip->beacon_interval = interval;
chip->beacon_set = true;
return usb_write_req((const u8 *)&chip->beacon_interval,
sizeof(chip->beacon_interval),
USB_REQ_BEACON_INTERVAL_WR);
}

int purelifi_chip_init_hw(struct purelifi_chip *chip)
{
u8 *addr = purelifi_mac_get_perm_addr(purelifi_chip_to_mac(chip));
struct usb_device *udev = interface_to_usbdev(chip->usb.intf);

pr_info("purelifi chip %02hx:%02hx v%02hx %02x-%02x-%02x %s\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct),
le16_to_cpu(udev->descriptor.bcdDevice),
addr[0], addr[1], addr[2],
speed(udev->speed));

return purelifi_set_beacon_interval(chip, 100, 0, 0);
}

int purelifi_chip_switch_radio(struct purelifi_chip *chip, u32 value)
{
int r;

r = usb_write_req((const u8 *)&value, sizeof(value), USB_REQ_POWER_WR);
if (r)
dev_err(purelifi_chip_dev(chip), "%s r=%d", __func__, r);
return r;
}

int purelifi_chip_enable_rxtx(struct purelifi_chip *chip)
{
purelifi_usb_enable_tx(&chip->usb);
return purelifi_usb_enable_rx(&chip->usb);
}

void purelifi_chip_disable_rxtx(struct purelifi_chip *chip)
{
u8 value;

value = 0;
usb_write_req((const u8 *)&value, sizeof(value), USB_REQ_RXTX_WR);
purelifi_usb_disable_rx(&chip->usb);
purelifi_usb_disable_tx(&chip->usb);
}

int purelifi_chip_set_rate(struct purelifi_chip *chip, u8 rate)
{
int r;
static struct purelifi_chip *chip_p;

if (chip)
chip_p = chip;
if (!chip_p)
return -EINVAL;

r = usb_write_req((const u8 *)&rate, sizeof(rate), USB_REQ_RATE_WR);
if (r)
dev_err(purelifi_chip_dev(chip), "set rate failed r=%d", r);
return r;
}

MODULE_LICENSE("GPL");
@@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef _LF_X_CHIP_H
#define _LF_X_CHIP_H

#include <net/mac80211.h>

#include "usb.h"

enum unit_type_t {
STA = 0,
AP = 1,
};

struct purelifi_chip {
struct purelifi_usb usb;
struct mutex mutex; /* lock to protect chip data */
enum unit_type_t unit_type;
u16 link_led;
u8 beacon_set;
u16 beacon_interval;
};

struct purelifi_mc_hash {
u32 low;
u32 high;
};

#define purelifi_chip_dev(chip) (&(chip)->usb.intf->dev)

void purelifi_chip_init(struct purelifi_chip *chip,
struct ieee80211_hw *hw,
struct usb_interface *intf);

void purelifi_chip_release(struct purelifi_chip *chip);

void purelifi_chip_disable_rxtx(struct purelifi_chip *chip);

int purelifi_chip_init_hw(struct purelifi_chip *chip);

int purelifi_chip_enable_rxtx(struct purelifi_chip *chip);

int purelifi_chip_set_rate(struct purelifi_chip *chip, u8 rate);

int purelifi_set_beacon_interval(struct purelifi_chip *chip, u16 interval,
u8 dtim_period, int type);

int purelifi_chip_switch_radio(struct purelifi_chip *chip, u32 value);

static inline struct purelifi_chip *purelifi_usb_to_chip(struct purelifi_usb
*usb)
{
return container_of(usb, struct purelifi_chip, usb);
}

static inline void purelifi_mc_clear(struct purelifi_mc_hash *hash)
{
hash->low = 0;
/* The interfaces must always received broadcasts.
* The hash of the broadcast address ff:ff:ff:ff:ff:ff is 63.
*/
hash->high = 0x80000000;
}

static inline void purelifi_mc_add_all(struct purelifi_mc_hash *hash)
{
hash->low = 0xffffffff;
hash->high = 0xffffffff;
}

static inline void purelifi_mc_add_addr(struct purelifi_mc_hash *hash,
u8 *addr
)
{
unsigned int i = addr[5] >> 2;

if (i < 32)
hash->low |= 1 << i;
else
hash->high |= 1 << (i - 32);
}
#endif /* _LF_X_CHIP_H */
@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef _PURELIFI_MAC_DRIVER_USB_INTERFACE
#define _PURELIFI_MAC_DRIVER_USB_INTERFACE
#define PURELIFI_BYTE_NUM_ALIGNMENT 4
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
#define AP_USER_LIMIT 8

struct rx_status {
u16 rssi;
u8 rate_idx;
u8 pad;
u64 crc_error_count;
} __packed;

enum usb_req_enum_t {
USB_REQ_TEST_WR = 0,
USB_REQ_MAC_WR = 1,
USB_REQ_POWER_WR = 2,
USB_REQ_RXTX_WR = 3,
USB_REQ_BEACON_WR = 4,
USB_REQ_BEACON_INTERVAL_WR = 5,
USB_REQ_RTS_CTS_RATE_WR = 6,
USB_REQ_HASH_WR = 7,
USB_REQ_DATA_TX = 8,
USB_REQ_RATE_WR = 9,
USB_REQ_SET_FREQ = 15
};

struct usb_req_t {
enum usb_req_enum_t id;
u32 len;
u8 buf[512];
};

#endif

0 comments on commit 2f1cd76

Please sign in to comment.