Skip to content

Commit

Permalink
wireless: Initial driver submission for pureLiFi STA devices
Browse files Browse the repository at this point in the history
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 Feb 12, 2021
1 parent 16ad7b4 commit 5d8fb5c
Show file tree
Hide file tree
Showing 15 changed files with 2,807 additions and 0 deletions.
5 changes: 5 additions & 0 deletions MAINTAINERS
Expand Up @@ -14447,6 +14447,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: Supported
F: drivers/net/wireless/purelifi

PVRUSB2 VIDEO4LINUX DRIVER
M: Mike Isely <isely@pobox.com>
L: pvrusb2@isely.net (subscribers-only)
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/Kconfig
Expand Up @@ -35,6 +35,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"
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/Makefile
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions drivers/net/wireless/purelifi/Kconfig
@@ -0,0 +1,17 @@
# SPDX-License-Identifier: GPL-2.0-only
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

source "drivers/net/wireless/purelifi/plfxlc/Kconfig"

endif # WLAN_VENDOR_PURELIFI
2 changes: 2 additions & 0 deletions drivers/net/wireless/purelifi/Makefile
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_WLAN_VENDOR_PURELIFI) := plfxlc/
13 changes: 13 additions & 0 deletions drivers/net/wireless/purelifi/plfxlc/Kconfig
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
config PLFXLC

tristate "pureLiFi X, XL, XC 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.

3 changes: 3 additions & 0 deletions drivers/net/wireless/purelifi/plfxlc/Makefile
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_PLFXLC) := plfxlc.o
plfxlc-objs += chip.o firmware.o usb.o mac.o
96 changes: 96 additions & 0 deletions drivers/net/wireless/purelifi/plfxlc/chip.c
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021 pureLiFi
*/

#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 %02x:%02x v%02x %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],
purelifi_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), "POWER_WR failed (%d)\n", 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)
{
static const u8 value;

usb_write_req(&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;

if (!chip)
return -EINVAL;

r = usb_write_req(&rate, sizeof(rate), USB_REQ_RATE_WR);
if (r)
dev_err(purelifi_chip_dev(chip), "RATE_WR failed (%d)\n", r);
return r;
}

MODULE_LICENSE("GPL");
84 changes: 84 additions & 0 deletions drivers/net/wireless/purelifi/plfxlc/chip.h
@@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021 pureLiFi
*/

#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 comments on commit 5d8fb5c

Please sign in to comment.