Commit caa6772d authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Staging: remove wusbcore and UWB from the kernel tree.

It's been over 6 months, and no one has noticed that these drivers are
deleted, probably because no one actually has this hardware.  As no one
has volunteered to maintain the code, let's drop it for good.

Link: https://lore.kernel.org/r/20200210231417.GA1736729@kroah.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4fb8b5aa
......@@ -3919,11 +3919,6 @@ F: certs/
F: scripts/sign-file.c
F: scripts/extract-cert.c
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
L: devel@driverdev.osuosl.org
S: Obsolete
F: drivers/staging/wusbcore/
CFAG12864B LCD DRIVER
M: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
S: Maintained
......@@ -17094,11 +17089,6 @@ S: Maintained
F: drivers/usb/common/ulpi.c
F: include/linux/ulpi/
ULTRA-WIDEBAND (UWB) SUBSYSTEM:
L: devel@driverdev.osuosl.org
S: Obsolete
F: drivers/staging/uwb/
UNICODE SUBSYSTEM:
M: Gabriel Krisman Bertazi <krisman@collabora.com>
L: linux-fsdevel@vger.kernel.org
......
......@@ -112,9 +112,6 @@ source "drivers/staging/fieldbus/Kconfig"
source "drivers/staging/kpc2000/Kconfig"
source "drivers/staging/wusbcore/Kconfig"
source "drivers/staging/uwb/Kconfig"
source "drivers/staging/exfat/Kconfig"
source "drivers/staging/qlge/Kconfig"
......
......@@ -46,8 +46,6 @@ obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
obj-$(CONFIG_KPC2000) += kpc2000/
obj-$(CONFIG_UWB) += uwb/
obj-$(CONFIG_USB_WUSB) += wusbcore/
obj-$(CONFIG_STAGING_EXFAT_FS) += exfat/
obj-$(CONFIG_QLGE) += qlge/
obj-$(CONFIG_NET_VENDOR_HP) += hp/
......
# SPDX-License-Identifier: GPL-2.0-only
#
# UWB device configuration
#
menuconfig UWB
tristate "Ultra Wideband devices"
default n
select GENERIC_NET_UTILS
help
UWB is a high-bandwidth, low-power, point-to-point radio
technology using a wide spectrum (3.1-10.6GHz). It is
optimized for in-room use (480Mbps at 2 meters, 110Mbps at
10m). It serves as the transport layer for other protocols,
such as Wireless USB (WUSB).
The topology is peer to peer; however, higher level
protocols (such as WUSB) might impose a master/slave
relationship.
Say Y here if your computer has UWB radio controllers (USB or PCI)
based. You will need to enable the radio controllers
below. It is ok to select all of them, no harm done.
For more help check the UWB and WUSB related files in
<file:Documentation/usb/>.
To compile the UWB stack as a module, choose M here.
if UWB
config UWB_HWA
tristate "UWB Radio Control driver for WUSB-compliant USB dongles (HWA)"
depends on USB
help
This driver enables the radio controller for HWA USB
devices. HWA stands for Host Wire Adapter, and it is a UWB
Radio Controller connected to your system via USB. Most of
them come with a Wireless USB host controller also.
To compile this driver select Y (built in) or M (module). It
is safe to select any even if you do not have the hardware.
config UWB_WHCI
tristate "UWB Radio Control driver for WHCI-compliant cards"
depends on PCI
help
This driver enables the radio controller for WHCI cards.
WHCI is a specification developed by Intel
(http://www.intel.com/technology/comms/wusb/whci.htm) much
in the spirit of USB's EHCI, but for UWB and Wireless USB
radio/host controllers connected via memory mapping (eg:
PCI). Most of these cards come also with a Wireless USB host
controller.
To compile this driver select Y (built in) or M (module). It
is safe to select any even if you do not have the hardware.
config UWB_I1480U
tristate "Support for Intel Wireless UWB Link 1480 HWA"
depends on UWB_HWA
select FW_LOADER
help
This driver enables support for the i1480 when connected via
USB. It consists of a firmware uploader that will enable it
to behave as an HWA device.
To compile this driver select Y (built in) or M (module). It
is safe to select any even if you do not have the hardware.
endif # UWB
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_UWB) += uwb.o
obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o
obj-$(CONFIG_UWB_HWA) += hwa-rc.o
obj-$(CONFIG_UWB_I1480U) += i1480/
uwb-objs := \
address.o \
allocator.o \
beacon.o \
driver.o \
drp.o \
drp-avail.o \
drp-ie.o \
est.o \
ie.o \
ie-rcv.o \
lc-dev.o \
lc-rc.o \
neh.o \
pal.o \
radio.o \
reset.o \
rsv.o \
scan.o \
uwb-debug.o \
uwbd.o
umc-objs := \
umc-bus.o \
umc-dev.o \
umc-drv.o
TODO: Remove in late 2019 unless there are users
There seems to not be any real wireless USB devices anywhere in the wild
anymore. It turned out to be a failed technology :(
This will be removed from the tree if no one objects.
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
// SPDX-License-Identifier: GPL-2.0-only
/*
* Ultra Wide Band
* Address management
*
* Copyright (C) 2005-2006 Intel Corporation
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
*
* FIXME: docs
*/
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/random.h>
#include <linux/etherdevice.h>
#include "uwb-internal.h"
/** Device Address Management command */
struct uwb_rc_cmd_dev_addr_mgmt {
struct uwb_rccb rccb;
u8 bmOperationType;
u8 baAddr[6];
} __attribute__((packed));
/**
* Low level command for setting/getting UWB radio's addresses
*
* @hwarc: HWA Radio Control interface instance
* @bmOperationType:
* Set/get, MAC/DEV (see WUSB1.0[8.6.2.2])
* @baAddr: address buffer--assumed to have enough data to hold
* the address type requested.
* @reply: Pointer to reply buffer (can be stack allocated)
* @returns: 0 if ok, < 0 errno code on error.
*
* @cmd has to be allocated because USB cannot grok USB or vmalloc
* buffers depending on your combination of host architecture.
*/
static
int uwb_rc_dev_addr_mgmt(struct uwb_rc *rc,
u8 bmOperationType, const u8 *baAddr,
struct uwb_rc_evt_dev_addr_mgmt *reply)
{
int result;
struct uwb_rc_cmd_dev_addr_mgmt *cmd;
result = -ENOMEM;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
goto error_kzalloc;
cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_DEV_ADDR_MGMT);
cmd->bmOperationType = bmOperationType;
if (baAddr) {
size_t size = 0;
switch (bmOperationType >> 1) {
case 0: size = 2; break;
case 1: size = 6; break;
default: BUG();
}
memcpy(cmd->baAddr, baAddr, size);
}
reply->rceb.bEventType = UWB_RC_CET_GENERAL;
reply->rceb.wEvent = UWB_RC_CMD_DEV_ADDR_MGMT;
result = uwb_rc_cmd(rc, "DEV-ADDR-MGMT",
&cmd->rccb, sizeof(*cmd),
&reply->rceb, sizeof(*reply));
if (result < 0)
goto error_cmd;
if (result < sizeof(*reply)) {
dev_err(&rc->uwb_dev.dev,
"DEV-ADDR-MGMT: not enough data replied: "
"%d vs %zu bytes needed\n", result, sizeof(*reply));
result = -ENOMSG;
} else if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
dev_err(&rc->uwb_dev.dev,
"DEV-ADDR-MGMT: command execution failed: %s (%d)\n",
uwb_rc_strerror(reply->bResultCode),
reply->bResultCode);
result = -EIO;
} else
result = 0;
error_cmd:
kfree(cmd);
error_kzalloc:
return result;
}
/**
* Set the UWB RC MAC or device address.
*
* @rc: UWB Radio Controller
* @_addr: Pointer to address to write [assumed to be either a
* 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *'].
* @type: Type of address to set (UWB_ADDR_DEV or UWB_ADDR_MAC).
* @returns: 0 if ok, < 0 errno code on error.
*
* Some anal retentivity here: even if both 'struct
* uwb_{dev,mac}_addr' have the actual byte array in the same offset
* and I could just pass _addr to hwarc_cmd_dev_addr_mgmt(), I prefer
* to use some syntatic sugar in case someday we decide to change the
* format of the structs. The compiler will optimize it out anyway.
*/
static int uwb_rc_addr_set(struct uwb_rc *rc,
const void *_addr, enum uwb_addr_type type)
{
int result;
u8 bmOperationType = 0x1; /* Set address */
const struct uwb_dev_addr *dev_addr = _addr;
const struct uwb_mac_addr *mac_addr = _addr;
struct uwb_rc_evt_dev_addr_mgmt reply;
const u8 *baAddr;
result = -EINVAL;
switch (type) {
case UWB_ADDR_DEV:
baAddr = dev_addr->data;
break;
case UWB_ADDR_MAC:
baAddr = mac_addr->data;
bmOperationType |= 0x2;
break;
default:
return result;
}
return uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &reply);
}
/**
* Get the UWB radio's MAC or device address.
*
* @rc: UWB Radio Controller
* @_addr: Where to write the address data [assumed to be either a
* 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *'].
* @type: Type of address to get (UWB_ADDR_DEV or UWB_ADDR_MAC).
* @returns: 0 if ok (and *_addr set), < 0 errno code on error.
*
* See comment in uwb_rc_addr_set() about anal retentivity in the
* type handling of the address variables.
*/
static int uwb_rc_addr_get(struct uwb_rc *rc,
void *_addr, enum uwb_addr_type type)
{
int result;
u8 bmOperationType = 0x0; /* Get address */
struct uwb_rc_evt_dev_addr_mgmt evt;
struct uwb_dev_addr *dev_addr = _addr;
struct uwb_mac_addr *mac_addr = _addr;
u8 *baAddr;
result = -EINVAL;
switch (type) {
case UWB_ADDR_DEV:
baAddr = dev_addr->data;
break;
case UWB_ADDR_MAC:
bmOperationType |= 0x2;
baAddr = mac_addr->data;
break;
default:
return result;
}
result = uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &evt);
if (result == 0)
switch (type) {
case UWB_ADDR_DEV:
memcpy(&dev_addr->data, evt.baAddr,
sizeof(dev_addr->data));
break;
case UWB_ADDR_MAC:
memcpy(&mac_addr->data, evt.baAddr,
sizeof(mac_addr->data));
break;
default: /* shut gcc up */
BUG();
}
return result;
}
/** Get @rc's MAC address to @addr */
int uwb_rc_mac_addr_get(struct uwb_rc *rc,
struct uwb_mac_addr *addr) {
return uwb_rc_addr_get(rc, addr, UWB_ADDR_MAC);
}
EXPORT_SYMBOL_GPL(uwb_rc_mac_addr_get);
/** Get @rc's device address to @addr */
int uwb_rc_dev_addr_get(struct uwb_rc *rc,
struct uwb_dev_addr *addr) {
return uwb_rc_addr_get(rc, addr, UWB_ADDR_DEV);
}
EXPORT_SYMBOL_GPL(uwb_rc_dev_addr_get);
/** Set @rc's address to @addr */
int uwb_rc_mac_addr_set(struct uwb_rc *rc,
const struct uwb_mac_addr *addr)
{
int result = -EINVAL;
mutex_lock(&rc->uwb_dev.mutex);
result = uwb_rc_addr_set(rc, addr, UWB_ADDR_MAC);
mutex_unlock(&rc->uwb_dev.mutex);
return result;
}
/** Set @rc's address to @addr */
int uwb_rc_dev_addr_set(struct uwb_rc *rc,
const struct uwb_dev_addr *addr)
{
int result = -EINVAL;
mutex_lock(&rc->uwb_dev.mutex);
result = uwb_rc_addr_set(rc, addr, UWB_ADDR_DEV);
rc->uwb_dev.dev_addr = *addr;
mutex_unlock(&rc->uwb_dev.mutex);
return result;
}
/* Returns !0 if given address is already assigned to device. */
int __uwb_mac_addr_assigned_check(struct device *dev, void *_addr)
{
struct uwb_dev *uwb_dev = to_uwb_dev(dev);
struct uwb_mac_addr *addr = _addr;
if (!uwb_mac_addr_cmp(addr, &uwb_dev->mac_addr))
return !0;
return 0;
}
/* Returns !0 if given address is already assigned to device. */
int __uwb_dev_addr_assigned_check(struct device *dev, void *_addr)
{
struct uwb_dev *uwb_dev = to_uwb_dev(dev);
struct uwb_dev_addr *addr = _addr;
if (!uwb_dev_addr_cmp(addr, &uwb_dev->dev_addr))
return !0;
return 0;
}
/**
* uwb_dev_addr_assign - assigned a generated DevAddr to a radio controller
* @rc: the (local) radio controller device requiring a new DevAddr
*
* A new DevAddr is required when:
* - first setting up a radio controller
* - if the hardware reports a DevAddr conflict
*
* The DevAddr is randomly generated in the generated DevAddr range
* [0x100, 0xfeff]. The number of devices in a beacon group is limited
* by mMaxBPLength (96) so this address space will never be exhausted.
*
* [ECMA-368] 17.1.1, 17.16.
*/
int uwb_rc_dev_addr_assign(struct uwb_rc *rc)
{
struct uwb_dev_addr new_addr;
do {
get_random_bytes(new_addr.data, sizeof(new_addr.data));
} while (new_addr.data[0] == 0x00 || new_addr.data[0] == 0xff
|| __uwb_dev_addr_assigned(rc, &new_addr));
return uwb_rc_dev_addr_set(rc, &new_addr);
}
/**
* uwbd_evt_handle_rc_dev_addr_conflict - handle a DEV_ADDR_CONFLICT event
* @evt: the DEV_ADDR_CONFLICT notification from the radio controller
*
* A new (non-conflicting) DevAddr is assigned to the radio controller.
*
* [ECMA-368] 17.1.1.1.
*/
int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt)
{
struct uwb_rc *rc = evt->rc;
return uwb_rc_dev_addr_assign(rc);
}
/*
* Print the 48-bit EUI MAC address of the radio controller when
* reading /sys/class/uwb_rc/XX/mac_address
*/
static ssize_t uwb_rc_mac_addr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct uwb_dev *uwb_dev = to_uwb_dev(dev);
struct uwb_rc *rc = uwb_dev->rc;
struct uwb_mac_addr addr;
ssize_t result;
mutex_lock(&rc->uwb_dev.mutex);
result = uwb_rc_addr_get(rc, &addr, UWB_ADDR_MAC);
mutex_unlock(&rc->uwb_dev.mutex);
if (result >= 0) {
result = uwb_mac_addr_print(buf, UWB_ADDR_STRSIZE, &addr);
buf[result++] = '\n';
}
return result;
}
/*
* Parse a 48 bit address written to /sys/class/uwb_rc/XX/mac_address
* and if correct, set it.
*/
static ssize_t uwb_rc_mac_addr_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct uwb_dev *uwb_dev = to_uwb_dev(dev);
struct uwb_rc *rc = uwb_dev->rc;
struct uwb_mac_addr addr;
ssize_t result;
if (!mac_pton(buf, addr.data))
return -EINVAL;
if (is_multicast_ether_addr(addr.data)) {
dev_err(&rc->uwb_dev.dev, "refusing to set multicast "
"MAC address %s\n", buf);
return -EINVAL;
}
result = uwb_rc_mac_addr_set(rc, &addr);
if (result == 0)
rc->uwb_dev.mac_addr = addr;
return result < 0 ? result : size;
}
DEVICE_ATTR(mac_address, S_IRUGO | S_IWUSR, uwb_rc_mac_addr_show, uwb_rc_mac_addr_store);
/** Print @addr to @buf, @return bytes written */
size_t __uwb_addr_print(char *buf, size_t buf_size, const unsigned char *addr,
int type)
{
size_t result;
if (type)
result = scnprintf(buf, buf_size, "%pM", addr);
else
result = scnprintf(buf, buf_size, "%02x:%02x",
addr[1], addr[0]);
return result;
}
EXPORT_SYMBOL_GPL(__uwb_addr_print);
// SPDX-License-Identifier: GPL-2.0-only
/*
* UWB reservation management.
*
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include "uwb.h"
#include "uwb-internal.h"
static void uwb_rsv_fill_column_alloc(struct uwb_rsv_alloc_info *ai)
{
int col, mas, safe_mas, unsafe_mas;
unsigned char *bm = ai->bm;
struct uwb_rsv_col_info *ci = ai->ci;
unsigned char c;
for (col = ci->csi.start_col; col < UWB_NUM_ZONES; col += ci->csi.interval) {
safe_mas = ci->csi.safe_mas_per_col;
unsafe_mas = ci->csi.unsafe_mas_per_col;
for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++ ) {
if (bm[col * UWB_MAS_PER_ZONE + mas] == 0) {
if (safe_mas > 0) {
safe_mas--;
c = UWB_RSV_MAS_SAFE;
} else if (unsafe_mas > 0) {
unsafe_mas--;
c = UWB_RSV_MAS_UNSAFE;
} else {
break;
}
bm[col * UWB_MAS_PER_ZONE + mas] = c;
}
}
}
}
static void uwb_rsv_fill_row_alloc(struct uwb_rsv_alloc_info *ai)
{
int mas, col, rows;
unsigned char *bm = ai->bm;
struct uwb_rsv_row_info *ri = &ai->ri;
unsigned char c;
rows = 1;
c = UWB_RSV_MAS_SAFE;
for (mas = UWB_MAS_PER_ZONE - 1; mas >= 0; mas--) {
if (ri->avail[mas] == 1) {
if (rows > ri->used_rows) {
break;
} else if (rows > 7) {
c = UWB_RSV_MAS_UNSAFE;
}
for (col = 0; col < UWB_NUM_ZONES; col++) {
if (bm[col * UWB_NUM_ZONES + mas] != UWB_RSV_MAS_NOT_AVAIL) {
bm[col * UWB_NUM_ZONES + mas] = c;
if(c == UWB_RSV_MAS_SAFE)
ai->safe_allocated_mases++;
else
ai->unsafe_allocated_mases++;
}
}
rows++;
}
}
ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases;
}
/*
* Find the best column set for a given availability, interval, num safe mas and
* num unsafe mas.
*
* The different sets are tried in order as shown below, depending on the interval.
*
* interval = 16
* deep = 0
* set 1 -> { 8 }
* deep = 1
* set 1 -> { 4 }
* set 2 -> { 12 }
* deep = 2
* set 1 -> { 2 }
* set 2 -> { 6 }
* set 3 -> { 10 }
* set 4 -> { 14 }
* deep = 3
* set 1 -> { 1 }
* set 2 -> { 3 }
* set 3 -> { 5 }
* set 4 -> { 7 }
* set 5 -> { 9 }
* set 6 -> { 11 }
* set 7 -> { 13 }
* set 8 -> { 15 }
*
* interval = 8
* deep = 0
* set 1 -> { 4 12 }
* deep = 1
* set 1 -> { 2 10 }
* set 2 -> { 6 14 }
* deep = 2
* set 1 -> { 1 9 }
* set 2 -> { 3 11 }
* set 3 -> { 5 13 }
* set 4 -> { 7 15 }
*
* interval = 4
* deep = 0
* set 1 -> { 2 6 10 14 }
* deep = 1
* set 1 -> { 1 5 9 13 }
* set 2 -> { 3 7 11 15 }
*
* interval = 2
* deep = 0
* set 1 -> { 1 3 5 7 9 11 13 15 }
*/
static int uwb_rsv_find_best_column_set(struct uwb_rsv_alloc_info *ai, int interval,
int num_safe_mas, int num_unsafe_mas)
{
struct uwb_rsv_col_info *ci = ai->ci;
struct uwb_rsv_col_set_info *csi = &ci->csi;
struct uwb_rsv_col_set_info tmp_csi;
int deep, set, col, start_col_deep, col_start_set;
int start_col, max_mas_in_set, lowest_max_mas_in_deep;
int n_mas;
int found = UWB_RSV_ALLOC_NOT_FOUND;
tmp_csi.start_col = 0;
start_col_deep = interval;
n_mas = num_unsafe_mas + num_safe_mas;
for (deep = 0; ((interval >> deep) & 0x1) == 0; deep++) {
start_col_deep /= 2;
col_start_set = 0;
lowest_max_mas_in_deep = UWB_MAS_PER_ZONE;
for (set = 1; set <= (1 << deep); set++) {
max_mas_in_set = 0;
start_col = start_col_deep + col_start_set;
for (col = start_col; col < UWB_NUM_ZONES; col += interval) {
if (ci[col].max_avail_safe >= num_safe_mas &&
ci[col].max_avail_unsafe >= n_mas) {
if (ci[col].highest_mas[n_mas] > max_mas_in_set)
max_mas_in_set = ci[col].highest_mas[n_mas];
} else {
max_mas_in_set = 0;
break;
}
}
if ((lowest_max_mas_in_deep > max_mas_in_set) && max_mas_in_set) {
lowest_max_mas_in_deep = max_mas_in_set;
tmp_csi.start_col = start_col;
}
col_start_set += (interval >> deep);
}
if (lowest_max_mas_in_deep < 8) {
csi->start_col = tmp_csi.start_col;
found = UWB_RSV_ALLOC_FOUND;
break;
} else if ((lowest_max_mas_in_deep > 8) &&
(lowest_max_mas_in_deep != UWB_MAS_PER_ZONE) &&
(found == UWB_RSV_ALLOC_NOT_FOUND)) {
csi->start_col = tmp_csi.start_col;
found = UWB_RSV_ALLOC_FOUND;
}
}
if (found == UWB_RSV_ALLOC_FOUND) {
csi->interval = interval;
csi->safe_mas_per_col = num_safe_mas;
csi->unsafe_mas_per_col = num_unsafe_mas;
ai->safe_allocated_mases = (UWB_NUM_ZONES / interval) * num_safe_mas;
ai->unsafe_allocated_mases = (UWB_NUM_ZONES / interval) * num_unsafe_mas;
ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases;
ai->interval = interval;
}
return found;
}
static void get_row_descriptors(struct uwb_rsv_alloc_info *ai)
{
unsigned char *bm = ai->bm;
struct uwb_rsv_row_info *ri = &ai->ri;
int col, mas;
ri->free_rows = 16;
for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) {
ri->avail[mas] = 1;
for (col = 1; col < UWB_NUM_ZONES; col++) {
if (bm[col * UWB_NUM_ZONES + mas] == UWB_RSV_MAS_NOT_AVAIL) {
ri->free_rows--;
ri->avail[mas]=0;
break;
}
}
}
}
static void uwb_rsv_fill_column_info(unsigned char *bm, int column, struct uwb_rsv_col_info *rci)
{
int mas;
int block_count = 0, start_block = 0;
int previous_avail = 0;
int available = 0;
int safe_mas_in_row[UWB_MAS_PER_ZONE] = {
8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1,
};
rci->max_avail_safe = 0;
for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) {
if (!bm[column * UWB_NUM_ZONES + mas]) {
available++;
rci->max_avail_unsafe = available;
rci->highest_mas[available] = mas;
if (previous_avail) {
block_count++;
if ((block_count > safe_mas_in_row[start_block]) &&
(!rci->max_avail_safe))
rci->max_avail_safe = available - 1;
} else {
previous_avail = 1;
start_block = mas;
block_count = 1;
}
} else {
previous_avail = 0;
}
}
if (!rci->max_avail_safe)
rci->max_avail_safe = rci->max_avail_unsafe;
}
static void get_column_descriptors(struct uwb_rsv_alloc_info *ai)
{
unsigned char *bm = ai->bm;
struct uwb_rsv_col_info *ci = ai->ci;
int col;
for (col = 1; col < UWB_NUM_ZONES; col++) {
uwb_rsv_fill_column_info(bm, col, &ci[col]);
}
}
static int uwb_rsv_find_best_row_alloc(struct uwb_rsv_alloc_info *ai)
{
int n_rows;
int max_rows = ai->max_mas / UWB_USABLE_MAS_PER_ROW;
int min_rows = ai->min_mas / UWB_USABLE_MAS_PER_ROW;
if (ai->min_mas % UWB_USABLE_MAS_PER_ROW)
min_rows++;
for (n_rows = max_rows; n_rows >= min_rows; n_rows--) {
if (n_rows <= ai->ri.free_rows) {
ai->ri.used_rows = n_rows;
ai->interval = 1; /* row reservation */
uwb_rsv_fill_row_alloc(ai);
return UWB_RSV_ALLOC_FOUND;
}
}
return UWB_RSV_ALLOC_NOT_FOUND;
}
static int uwb_rsv_find_best_col_alloc(struct uwb_rsv_alloc_info *ai, int interval)
{
int n_safe, n_unsafe, n_mas;
int n_column = UWB_NUM_ZONES / interval;
int max_per_zone = ai->max_mas / n_column;
int min_per_zone = ai->min_mas / n_column;
if (ai->min_mas % n_column)
min_per_zone++;
if (min_per_zone > UWB_MAS_PER_ZONE) {
return UWB_RSV_ALLOC_NOT_FOUND;
}
if (max_per_zone > UWB_MAS_PER_ZONE) {
max_per_zone = UWB_MAS_PER_ZONE;
}
for (n_mas = max_per_zone; n_mas >= min_per_zone; n_mas--) {
if (uwb_rsv_find_best_column_set(ai, interval, 0, n_mas) == UWB_RSV_ALLOC_NOT_FOUND)
continue;
for (n_safe = n_mas; n_safe >= 0; n_safe--) {
n_unsafe = n_mas - n_safe;
if (uwb_rsv_find_best_column_set(ai, interval, n_safe, n_unsafe) == UWB_RSV_ALLOC_FOUND) {
uwb_rsv_fill_column_alloc(ai);
return UWB_RSV_ALLOC_FOUND;
}
}
}
return UWB_RSV_ALLOC_NOT_FOUND;
}
int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *available,
struct uwb_mas_bm *result)
{
struct uwb_rsv_alloc_info *ai;
int interval;
int bit_index;
ai = kzalloc(sizeof(struct uwb_rsv_alloc_info), GFP_KERNEL);
if (!ai)
return UWB_RSV_ALLOC_NOT_FOUND;
ai->min_mas = rsv->min_mas;
ai->max_mas = rsv->max_mas;
ai->max_interval = rsv->max_interval;
/* fill the not available vector from the available bm */
for_each_clear_bit(bit_index, available->bm, UWB_NUM_MAS)
ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL;
if (ai->max_interval == 1) {
get_row_descriptors(ai);
if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND)
goto alloc_found;
else
goto alloc_not_found;
}
get_column_descriptors(ai);
for (interval = 16; interval >= 2; interval>>=1) {
if (interval > ai->max_interval)
continue;
if (uwb_rsv_find_best_col_alloc(ai, interval) == UWB_RSV_ALLOC_FOUND)
goto alloc_found;
}
/* try row reservation if no column is found */
get_row_descriptors(ai);
if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND)
goto alloc_found;
else
goto alloc_not_found;
alloc_found:
bitmap_zero(result->bm, UWB_NUM_MAS);
bitmap_zero(result->unsafe_bm, UWB_NUM_MAS);
/* fill the safe and unsafe bitmaps */
for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) {
if (ai->bm[bit_index] == UWB_RSV_MAS_SAFE)
set_bit(bit_index, result->bm);
else if (ai->bm[bit_index] == UWB_RSV_MAS_UNSAFE)
set_bit(bit_index, result->unsafe_bm);
}
bitmap_or(result->bm, result->bm, result->unsafe_bm, UWB_NUM_MAS);
result->safe = ai->safe_allocated_mases;
result->unsafe = ai->unsafe_allocated_mases;
kfree(ai);
return UWB_RSV_ALLOC_FOUND;
alloc_not_found:
kfree(ai);
return UWB_RSV_ALLOC_NOT_FOUND;
}
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Ultra Wide Band
* Driver initialization, etc
*
* Copyright (C) 2005-2006 Intel Corporation
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
*
* FIXME: docs
*
* Life cycle: FIXME: explain
*
* UWB radio controller:
*
* 1. alloc a uwb_rc, zero it
* 2. call uwb_rc_init() on it to set it up + ops (won't do any
* kind of allocation)
* 3. register (now it is owned by the UWB stack--deregister before
* freeing/destroying).
* 4. It lives on it's own now (UWB stack handles)--when it
* disconnects, call unregister()
* 5. free it.
*
* Make sure you have a reference to the uwb_rc before calling
* any of the UWB API functions.
*
* TODO:
*
* 1. Locking and life cycle management is crappy still. All entry
* points to the UWB HCD API assume you have a reference on the
* uwb_rc structure and that it won't go away. They mutex lock it
* before doing anything.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kdev_t.h>
#include <linux/random.h>
#include "uwb-internal.h"
/* UWB stack attributes (or 'global' constants) */
/**
* If a beacon disappears for longer than this, then we consider the
* device who was represented by that beacon to be gone.
*
* ECMA-368[17.2.3, last para] establishes that a device must not
* consider a device to be its neighbour if he doesn't receive a beacon
* for more than mMaxLostBeacons. mMaxLostBeacons is defined in
* ECMA-368[17.16] as 3; because we can get only one beacon per
* superframe, that'd be 3 * 65ms = 195 ~ 200 ms. Let's give it time
* for jitter and stuff and make it 500 ms.
*/
unsigned long beacon_timeout_ms = 500;
static
ssize_t beacon_timeout_ms_show(struct class *class,
struct class_attribute *attr,
char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms);
}
static
ssize_t beacon_timeout_ms_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t size)
{
unsigned long bt;
ssize_t result;
result = sscanf(buf, "%lu", &bt);
if (result != 1)
return -EINVAL;
beacon_timeout_ms = bt;
return size;
}
static CLASS_ATTR_RW(beacon_timeout_ms);
static struct attribute *uwb_class_attrs[] = {
&class_attr_beacon_timeout_ms.attr,
NULL,
};
ATTRIBUTE_GROUPS(uwb_class);
/** Device model classes */
struct class uwb_rc_class = {
.name = "uwb_rc",
.class_groups = uwb_class_groups,
};
static int __init uwb_subsys_init(void)
{
int result = 0;
result = uwb_est_create();
if (result < 0) {
printk(KERN_ERR "uwb: Can't initialize EST subsystem\n");
goto error_est_init;
}
result = class_register(&uwb_rc_class);
if (result < 0)
goto error_uwb_rc_class_register;
/* Register the UWB bus */
result = bus_register(&uwb_bus_type);
if (result) {
pr_err("%s - registering bus driver failed\n", __func__);
goto exit_bus;
}
uwb_dbg_init();
return 0;
exit_bus:
class_unregister(&uwb_rc_class);
error_uwb_rc_class_register:
uwb_est_destroy();
error_est_init:
return result;
}
module_init(uwb_subsys_init);
static void __exit uwb_subsys_exit(void)
{
uwb_dbg_exit();
bus_unregister(&uwb_bus_type);
class_unregister(&uwb_rc_class);
uwb_est_destroy();
return;
}
module_exit(uwb_subsys_exit);
MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
MODULE_DESCRIPTION("Ultra Wide Band core");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0-only
/*
* Ultra Wide Band
* DRP availability management
*
* Copyright (C) 2005-2006 Intel Corporation
* Reinette Chatre <reinette.chatre@intel.com>
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
*
* Manage DRP Availability (the MAS available for DRP
* reservations). Thus:
*
* - Handle DRP Availability Change notifications
*
* - Allow the reservation manager to indicate MAS reserved/released
* by local (owned by/targeted at the radio controller)
* reservations.
*
* - Based on the two sources above, generate a DRP Availability IE to
* be included in the beacon.
*
* See also the documentation for struct uwb_drp_avail.
*/
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/bitmap.h>
#include "uwb-internal.h"
/**
* uwb_drp_avail_init - initialize an RC's MAS availability
*
* All MAS are available initially. The RC will inform use which
* slots are used for the BP (it may change in size).
*/
void uwb_drp_avail_init(struct uwb_rc *rc)
{
bitmap_fill(rc->drp_avail.global, UWB_NUM_MAS);
bitmap_fill(rc->drp_avail.local, UWB_NUM_MAS);
bitmap_fill(rc->drp_avail.pending, UWB_NUM_MAS);
}
/*
* Determine MAS available for new local reservations.
*
* avail = global & local & pending
*/
void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail)
{
bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS);
}
/**
* uwb_drp_avail_reserve_pending - reserve MAS for a new reservation
* @rc: the radio controller
* @mas: the MAS to reserve
*
* Returns 0 on success, or -EBUSY if the MAS requested aren't available.
*/
int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas)
{
struct uwb_mas_bm avail;
uwb_drp_available(rc, &avail);
if (!bitmap_subset(mas->bm, avail.bm, UWB_NUM_MAS))
return -EBUSY;
bitmap_andnot(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
return 0;
}
/**
* uwb_drp_avail_reserve - reserve MAS for an established reservation
* @rc: the radio controller
* @mas: the MAS to reserve
*/
void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas)
{
bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
bitmap_andnot(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS);
rc->drp_avail.ie_valid = false;
}
/**
* uwb_drp_avail_release - release MAS from a pending or established reservation
* @rc: the radio controller
* @mas: the MAS to release
*/
void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas)
{
bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS);
bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
rc->drp_avail.ie_valid = false;
uwb_rsv_handle_drp_avail_change(rc);
}
/**
* uwb_drp_avail_ie_update - update the DRP Availability IE
* @rc: the radio controller
*
* avail = global & local
*/
void uwb_drp_avail_ie_update(struct uwb_rc *rc)
{
struct uwb_mas_bm avail;
bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY;
rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8;
uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail);
rc->drp_avail.ie_valid = true;
}
/**
* Create an unsigned long from a buffer containing a byte stream.
*
* @array: pointer to buffer
* @itr: index of buffer from where we start
* @len: the buffer's remaining size may not be exact multiple of
* sizeof(unsigned long), @len is the length of buffer that needs
* to be converted. This will be sizeof(unsigned long) or smaller
* (BUG if not). If it is smaller then we will pad the remaining
* space of the result with zeroes.
*/
static
unsigned long get_val(u8 *array, size_t itr, size_t len)
{
unsigned long val = 0;
size_t top = itr + len;
BUG_ON(len > sizeof(val));
while (itr < top) {
val <<= 8;
val |= array[top - 1];
top--;
}
val <<= 8 * (sizeof(val) - len); /* padding */
return val;
}
/**
* Initialize bitmap from data buffer.
*
* The bitmap to be converted could come from a IE, for example a
* DRP Availability IE.
* From ECMA-368 1.0 [16.8.7]: "
* octets: 1 1 N * (0 to 32)
* Element ID Length (=N) DRP Availability Bitmap
*
* The DRP Availability Bitmap field is up to 256 bits long, one
* bit for each MAS in the superframe, where the least-significant
* bit of the field corresponds to the first MAS in the superframe
* and successive bits correspond to successive MASs."
*
* The DRP Availability bitmap is in octets from 0 to 32, so octet
* 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32
* octets, the bits in octets not included at the end of the bitmap are
* treated as zero. In this case (when the bitmap is smaller than 32
* octets) the MAS represented range from MAS 1 to MAS (size of bitmap)
* with the last octet still containing bits for MAS 1-8, etc.
*
* For example:
* F00F0102 03040506 0708090A 0B0C0D0E 0F010203
* ^^^^
* ||||
* ||||
* |||\LSB of byte is MAS 9
* ||\MSB of byte is MAS 16
* |\LSB of first byte is MAS 1
* \ MSB of byte is MAS 8
*
* An example of this encoding can be found in ECMA-368 Annex-D [Table D.11]
*
* The resulting bitmap will have the following mapping:
* bit position 0 == MAS 1
* bit position 1 == MAS 2
* ...
* bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS
*
* @bmp_itr: pointer to bitmap (can be declared with DECLARE_BITMAP)
* @buffer: pointer to buffer containing bitmap data in big endian
* format (MSB first)
* @buffer_size:number of bytes with which bitmap should be initialized
*/
static
void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer,
size_t buffer_size)
{
u8 *buffer = _buffer;
size_t itr, len;
unsigned long val;
itr = 0;
while (itr < buffer_size) {
len = buffer_size - itr >= sizeof(val) ?
sizeof(val) : buffer_size - itr;
val = get_val(buffer, itr, len);
bmp_itr[itr / sizeof(val)] = val;
itr += sizeof(val);
}
}
/**
* Extract DRP Availability bitmap from the notification.
*
* The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes
* We convert that to our internal representation.
*/
static
int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp)
{
struct device *dev = &evt->rc->uwb_dev.dev;
struct uwb_rc_evt_drp_avail *drp_evt;
int result = -EINVAL;
/* Is there enough data to decode the event? */
if (evt->notif.size < sizeof(*drp_evt)) {
dev_err(dev, "DRP Availability Change: Not enough "
"data to decode event [%zu bytes, %zu "
"needed]\n", evt->notif.size, sizeof(*drp_evt));
goto error;
}
drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb);
buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8);
result = 0;
error:
return result;
}
/**
* Process an incoming DRP Availability notification.
*
* @evt: Event information (packs the actual event data, which
* radio controller it came to, etc).
*
* @returns: 0 on success (so uwbd() frees the event buffer), < 0
* on error.
*
* According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that
* the MAS slot is available, bits set to ZERO indicate that the slot
* is busy.
*
* So we clear available slots, we set used slots :)
*
* The notification only marks non-availability based on the BP and
* received DRP IEs that are not for this radio controller. A copy of
* this bitmap is needed to generate the real availability (which
* includes local and pending reservations).
*
* The DRP Availability IE that this radio controller emits will need
* to be updated.
*/
int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt)
{
int result;
struct uwb_rc *rc = evt->rc;
DECLARE_BITMAP(bmp, UWB_NUM_MAS);
result = uwbd_evt_get_drp_avail(evt, bmp);
if (result < 0)
return result;
mutex_lock(&rc->rsvs_mutex);
bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS);
rc->drp_avail.ie_valid = false;
uwb_rsv_handle_drp_avail_change(rc);
mutex_unlock(&rc->rsvs_mutex);
uwb_rsv_sched_update(rc);
return 0;
}
// SPDX-License-Identifier: GPL-2.0-only
/*
* UWB DRP IE management.
*
* Copyright (C) 2005-2006 Intel Corporation
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
*/
#include <linux/kernel.h>
#include <linux/random.h>
#include <linux/slab.h>
#include "uwb.h"
#include "uwb-internal.h"
/*
* Return the reason code for a reservations's DRP IE.
*/
static int uwb_rsv_reason_code(struct uwb_rsv *rsv)
{
static const int reason_codes[] = {
[UWB_RSV_STATE_O_INITIATED] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_O_PENDING] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_O_MODIFIED] = UWB_DRP_REASON_MODIFIED,
[UWB_RSV_STATE_O_ESTABLISHED] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_O_TO_BE_MOVED] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_O_MOVE_COMBINING] = UWB_DRP_REASON_MODIFIED,
[UWB_RSV_STATE_O_MOVE_REDUCING] = UWB_DRP_REASON_MODIFIED,
[UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_T_ACCEPTED] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_T_CONFLICT] = UWB_DRP_REASON_CONFLICT,
[UWB_RSV_STATE_T_PENDING] = UWB_DRP_REASON_PENDING,
[UWB_RSV_STATE_T_DENIED] = UWB_DRP_REASON_DENIED,
[UWB_RSV_STATE_T_RESIZED] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT,
[UWB_RSV_STATE_T_EXPANDING_PENDING] = UWB_DRP_REASON_PENDING,
[UWB_RSV_STATE_T_EXPANDING_DENIED] = UWB_DRP_REASON_DENIED,
};
return reason_codes[rsv->state];
}
/*
* Return the reason code for a reservations's companion DRP IE .
*/
static int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv)
{
static const int companion_reason_codes[] = {
[UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED,
[UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT,
[UWB_RSV_STATE_T_EXPANDING_PENDING] = UWB_DRP_REASON_PENDING,
[UWB_RSV_STATE_T_EXPANDING_DENIED] = UWB_DRP_REASON_DENIED,
};
return companion_reason_codes[rsv->state];
}
/*
* Return the status bit for a reservations's DRP IE.
*/
int uwb_rsv_status(struct uwb_rsv *rsv)
{
static const int statuses[] = {
[UWB_RSV_STATE_O_INITIATED] = 0,
[UWB_RSV_STATE_O_PENDING] = 0,
[UWB_RSV_STATE_O_MODIFIED] = 1,
[UWB_RSV_STATE_O_ESTABLISHED] = 1,
[UWB_RSV_STATE_O_TO_BE_MOVED] = 0,
[UWB_RSV_STATE_O_MOVE_COMBINING] = 1,
[UWB_RSV_STATE_O_MOVE_REDUCING] = 1,
[UWB_RSV_STATE_O_MOVE_EXPANDING] = 1,
[UWB_RSV_STATE_T_ACCEPTED] = 1,
[UWB_RSV_STATE_T_CONFLICT] = 0,
[UWB_RSV_STATE_T_PENDING] = 0,
[UWB_RSV_STATE_T_DENIED] = 0,
[UWB_RSV_STATE_T_RESIZED] = 1,
[UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1,
[UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 1,
[UWB_RSV_STATE_T_EXPANDING_PENDING] = 1,
[UWB_RSV_STATE_T_EXPANDING_DENIED] = 1,
};
return statuses[rsv->state];
}
/*
* Return the status bit for a reservations's companion DRP IE .
*/
int uwb_rsv_companion_status(struct uwb_rsv *rsv)
{
static const int companion_statuses[] = {
[UWB_RSV_STATE_O_MOVE_EXPANDING] = 0,
[UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1,
[UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 0,
[UWB_RSV_STATE_T_EXPANDING_PENDING] = 0,
[UWB_RSV_STATE_T_EXPANDING_DENIED] = 0,
};
return companion_statuses[rsv->state];
}
/*
* Allocate a DRP IE.
*
* To save having to free/allocate a DRP IE when its MAS changes,
* enough memory is allocated for the maxiumum number of DRP
* allocation fields. This gives an overhead per reservation of up to
* (UWB_NUM_ZONES - 1) * 4 = 60 octets.
*/
static struct uwb_ie_drp *uwb_drp_ie_alloc(void)
{
struct uwb_ie_drp *drp_ie;
drp_ie = kzalloc(struct_size(drp_ie, allocs, UWB_NUM_ZONES),
GFP_KERNEL);
if (drp_ie)
drp_ie->hdr.element_id = UWB_IE_DRP;
return drp_ie;
}
/*
* Fill a DRP IE's allocation fields from a MAS bitmap.
*/
static void uwb_drp_ie_from_bm(struct uwb_ie_drp *drp_ie,
struct uwb_mas_bm *mas)
{
int z, i, num_fields = 0, next = 0;
struct uwb_drp_alloc *zones;
__le16 current_bmp;
DECLARE_BITMAP(tmp_bmp, UWB_NUM_MAS);
DECLARE_BITMAP(tmp_mas_bm, UWB_MAS_PER_ZONE);
zones = drp_ie->allocs;
bitmap_copy(tmp_bmp, mas->bm, UWB_NUM_MAS);
/* Determine unique MAS bitmaps in zones from bitmap. */
for (z = 0; z < UWB_NUM_ZONES; z++) {
bitmap_copy(tmp_mas_bm, tmp_bmp, UWB_MAS_PER_ZONE);
if (bitmap_weight(tmp_mas_bm, UWB_MAS_PER_ZONE) > 0) {
bool found = false;
current_bmp = (__le16) *tmp_mas_bm;
for (i = 0; i < next; i++) {
if (current_bmp == zones[i].mas_bm) {
zones[i].zone_bm |= 1 << z;
found = true;
break;
}
}
if (!found) {
num_fields++;
zones[next].zone_bm = 1 << z;
zones[next].mas_bm = current_bmp;
next++;
}
}
bitmap_shift_right(tmp_bmp, tmp_bmp, UWB_MAS_PER_ZONE, UWB_NUM_MAS);
}
/* Store in format ready for transmission (le16). */
for (i = 0; i < num_fields; i++) {
drp_ie->allocs[i].zone_bm = cpu_to_le16(zones[i].zone_bm);
drp_ie->allocs[i].mas_bm = cpu_to_le16(zones[i].mas_bm);
}
drp_ie->hdr.length = sizeof(struct uwb_ie_drp) - sizeof(struct uwb_ie_hdr)
+ num_fields * sizeof(struct uwb_drp_alloc);
}
/**
* uwb_drp_ie_update - update a reservation's DRP IE
* @rsv: the reservation
*/
int uwb_drp_ie_update(struct uwb_rsv *rsv)
{
struct uwb_ie_drp *drp_ie;
struct uwb_rsv_move *mv;
int unsafe;
if (rsv->state == UWB_RSV_STATE_NONE) {
kfree(rsv->drp_ie);
rsv->drp_ie = NULL;
return 0;
}
unsafe = rsv->mas.unsafe ? 1 : 0;
if (rsv->drp_ie == NULL) {
rsv->drp_ie = uwb_drp_ie_alloc();
if (rsv->drp_ie == NULL)
return -ENOMEM;
}
drp_ie = rsv->drp_ie;
uwb_ie_drp_set_unsafe(drp_ie, unsafe);
uwb_ie_drp_set_tiebreaker(drp_ie, rsv->tiebreaker);
uwb_ie_drp_set_owner(drp_ie, uwb_rsv_is_owner(rsv));
uwb_ie_drp_set_status(drp_ie, uwb_rsv_status(rsv));
uwb_ie_drp_set_reason_code(drp_ie, uwb_rsv_reason_code(rsv));
uwb_ie_drp_set_stream_index(drp_ie, rsv->stream);
uwb_ie_drp_set_type(drp_ie, rsv->type);
if (uwb_rsv_is_owner(rsv)) {
switch (rsv->target.type) {
case UWB_RSV_TARGET_DEV:
drp_ie->dev_addr = rsv->target.dev->dev_addr;
break;
case UWB_RSV_TARGET_DEVADDR:
drp_ie->dev_addr = rsv->target.devaddr;
break;
}
} else
drp_ie->dev_addr = rsv->owner->dev_addr;
uwb_drp_ie_from_bm(drp_ie, &rsv->mas);
if (uwb_rsv_has_two_drp_ies(rsv)) {
mv = &rsv->mv;
if (mv->companion_drp_ie == NULL) {
mv->companion_drp_ie = uwb_drp_ie_alloc();
if (mv->companion_drp_ie == NULL)
return -ENOMEM;
}
drp_ie = mv->companion_drp_ie;
/* keep all the same configuration of the main drp_ie */
memcpy(drp_ie, rsv->drp_ie, sizeof(struct uwb_ie_drp));
/* FIXME: handle properly the unsafe bit */
uwb_ie_drp_set_unsafe(drp_ie, 1);
uwb_ie_drp_set_status(drp_ie, uwb_rsv_companion_status(rsv));
uwb_ie_drp_set_reason_code(drp_ie, uwb_rsv_companion_reason_code(rsv));
uwb_drp_ie_from_bm(drp_ie, &mv->companion_mas);
}
rsv->ie_valid = true;
return 0;
}
/*
* Set MAS bits from given MAS bitmap in a single zone of large bitmap.
*
* We are given a zone id and the MAS bitmap of bits that need to be set in
* this zone. Note that this zone may already have bits set and this only
* adds settings - we cannot simply assign the MAS bitmap contents to the
* zone contents. We iterate over the the bits (MAS) in the zone and set the
* bits that are set in the given MAS bitmap.
*/
static
void uwb_drp_ie_single_zone_to_bm(struct uwb_mas_bm *bm, u8 zone, u16 mas_bm)
{
int mas;
u16 mas_mask;
for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++) {
mas_mask = 1 << mas;
if (mas_bm & mas_mask)
set_bit(zone * UWB_NUM_ZONES + mas, bm->bm);
}
}
/**
* uwb_drp_ie_zones_to_bm - convert DRP allocation fields to a bitmap
* @mas: MAS bitmap that will be populated to correspond to the
* allocation fields in the DRP IE
* @drp_ie: the DRP IE that contains the allocation fields.
*
* The input format is an array of MAS allocation fields (16 bit Zone
* bitmap, 16 bit MAS bitmap) as described in [ECMA-368] section
* 16.8.6. The output is a full 256 bit MAS bitmap.
*
* We go over all the allocation fields, for each allocation field we
* know which zones are impacted. We iterate over all the zones
* impacted and call a function that will set the correct MAS bits in
* each zone.
*/
void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie)
{
int numallocs = (drp_ie->hdr.length - 4) / 4;
const struct uwb_drp_alloc *alloc;
int cnt;
u16 zone_bm, mas_bm;
u8 zone;
u16 zone_mask;
bitmap_zero(bm->bm, UWB_NUM_MAS);
for (cnt = 0; cnt < numallocs; cnt++) {
alloc = &drp_ie->allocs[cnt];
zone_bm = le16_to_cpu(alloc->zone_bm);
mas_bm = le16_to_cpu(alloc->mas_bm);
for (zone = 0; zone < UWB_NUM_ZONES; zone++) {
zone_mask = 1 << zone;
if (zone_bm & zone_mask)
uwb_drp_ie_single_zone_to_bm(bm, zone, mas_bm);
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_UWB_I1480U) += i1480-dfu-usb.o
i1480-dfu-usb-objs := \
dfu.o \
mac.o \
phy.o \
usb.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel Wireless UWB Link 1480
* Main driver
*
* Copyright (C) 2005-2006 Intel Corporation
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
*
* Common code for firmware upload used by the USB and PCI version;
* i1480_fw_upload() takes a device descriptor and uses the function
* pointers it provides to upload firmware and prepare the PHY.
*
* As well, provides common functions used by the rest of the code.
*/
#include "i1480-dfu.h"
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/random.h>
#include <linux/export.h>
#include "../../uwb.h"
/*
* i1480_rceb_check - Check RCEB for expected field values
* @i1480: pointer to device for which RCEB is being checked
* @rceb: RCEB being checked
* @cmd: which command the RCEB is related to
* @context: expected context
* @expected_type: expected event type
* @expected_event: expected event
*
* If @cmd is NULL, do not print error messages, but still return an error
* code.
*
* Return 0 if @rceb matches the expected values, -EINVAL otherwise.
*/
int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb,
const char *cmd, u8 context, u8 expected_type,
unsigned expected_event)
{
int result = 0;
struct device *dev = i1480->dev;
if (rceb->bEventContext != context) {
if (cmd)
dev_err(dev, "%s: unexpected context id 0x%02x "
"(expected 0x%02x)\n", cmd,
rceb->bEventContext, context);
result = -EINVAL;
}
if (rceb->bEventType != expected_type) {
if (cmd)
dev_err(dev, "%s: unexpected event type 0x%02x "
"(expected 0x%02x)\n", cmd,
rceb->bEventType, expected_type);
result = -EINVAL;
}
if (le16_to_cpu(rceb->wEvent) != expected_event) {
if (cmd)
dev_err(dev, "%s: unexpected event 0x%04x "
"(expected 0x%04x)\n", cmd,
le16_to_cpu(rceb->wEvent), expected_event);
result = -EINVAL;
}
return result;
}
EXPORT_SYMBOL_GPL(i1480_rceb_check);
/*
* Execute a Radio Control Command
*
* Command data has to be in i1480->cmd_buf.
*
* @returns size of the reply data filled in i1480->evt_buf or < 0 errno
* code on error.
*/
ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size,
size_t reply_size)
{
ssize_t result;
struct uwb_rceb *reply = i1480->evt_buf;
struct uwb_rccb *cmd = i1480->cmd_buf;
u16 expected_event = reply->wEvent;
u8 expected_type = reply->bEventType;
u8 context;
init_completion(&i1480->evt_complete);
i1480->evt_result = -EINPROGRESS;
do {
get_random_bytes(&context, 1);
} while (context == 0x00 || context == 0xff);
cmd->bCommandContext = context;
result = i1480->cmd(i1480, cmd_name, cmd_size);
if (result < 0)
goto error;
/* wait for the callback to report a event was received */
result = wait_for_completion_interruptible_timeout(
&i1480->evt_complete, HZ);
if (result == 0) {
result = -ETIMEDOUT;
goto error;
}
if (result < 0)
goto error;
result = i1480->evt_result;
if (result < 0) {
dev_err(i1480->dev, "%s: command reply reception failed: %zd\n",
cmd_name, result);
goto error;
}
/*
* Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a
* spurious notification after firmware is downloaded. So check whether
* the receibed RCEB is such notification before assuming that the
* command has failed.
*/
if (i1480_rceb_check(i1480, i1480->evt_buf, NULL,
0, 0xfd, 0x0022) == 0) {
/* Now wait for the actual RCEB for this command. */
result = i1480->wait_init_done(i1480);
if (result < 0)
goto error;
result = i1480->evt_result;
}
if (result != reply_size) {
dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n",
cmd_name, result, reply_size);
result = -EINVAL;
goto error;
}
/* Verify we got the right event in response */
result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context,
expected_type, expected_event);
error:
return result;
}
EXPORT_SYMBOL_GPL(i1480_cmd);
static
int i1480_print_state(struct i1480 *i1480)
{
int result;
u32 *buf = (u32 *) i1480->cmd_buf;
result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf));
if (result < 0) {
dev_err(i1480->dev, "cannot read U & L states: %d\n", result);
goto error;
}
dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]);
error:
return result;
}
/*
* PCI probe, firmware uploader
*
* _mac_fw_upload() will call rc_setup(), which needs an rc_release().
*/
int i1480_fw_upload(struct i1480 *i1480)
{
int result;
result = i1480_pre_fw_upload(i1480); /* PHY pre fw */
if (result < 0 && result != -ENOENT) {
i1480_print_state(i1480);
goto error;
}
result = i1480_mac_fw_upload(i1480); /* MAC fw */
if (result < 0) {
if (result == -ENOENT)
dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n",
i1480->mac_fw_name);
else
i1480_print_state(i1480);
goto error;
}
result = i1480_phy_fw_upload(i1480); /* PHY fw */
if (result < 0 && result != -ENOENT) {
i1480_print_state(i1480);
goto error_rc_release;
}
/*
* FIXME: find some reliable way to check whether firmware is running
* properly. Maybe use some standard request that has no side effects?
*/
dev_info(i1480->dev, "firmware uploaded successfully\n");
error_rc_release:
if (i1480->rc_release)
i1480->rc_release(i1480);
result = 0;
error:
return result;
}
EXPORT_SYMBOL_GPL(i1480_fw_upload);
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* i1480 Device Firmware Upload
*
* Copyright (C) 2005-2006 Intel Corporation
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
*
* This driver is the firmware uploader for the Intel Wireless UWB
* Link 1480 device (both in the USB and PCI incarnations).
*
* The process is quite simple: we stop the device, write the firmware
* to its memory and then restart it. Wait for the device to let us
* know it is done booting firmware. Ready.
*
* We might have to upload before or after a phy firmware (which might
* be done in two methods, using a normal firmware image or through
* the MPI port).
*
* Because USB and PCI use common methods, we just make ops out of the
* common operations (read, write, wait_init_done and cmd) and
* implement them in usb.c and pci.c.
*
* The flow is (some parts omitted):
*
* i1480_{usb,pci}_probe() On enumerate/discovery
* i1480_fw_upload()
* i1480_pre_fw_upload()
* __mac_fw_upload()
* fw_hdrs_load()
* mac_fw_hdrs_push()
* i1480->write() [i1480_{usb,pci}_write()]
* i1480_fw_cmp()
* i1480->read() [i1480_{usb,pci}_read()]
* i1480_mac_fw_upload()
* __mac_fw_upload()
* i1480->setup(()
* i1480->wait_init_done()
* i1480_cmd_reset()
* i1480->cmd() [i1480_{usb,pci}_cmd()]
* ...
* i1480_phy_fw_upload()
* request_firmware()
* i1480_mpi_write()
* i1480->cmd() [i1480_{usb,pci}_cmd()]
*
* Once the probe function enumerates the device and uploads the
* firmware, we just exit with -ENODEV, as we don't really want to
* attach to the device.
*/
#ifndef __i1480_DFU_H__
#define __i1480_DFU_H__
#include <linux/types.h>
#include <linux/completion.h>
#include "../../include/spec.h"
#define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018))
#if i1480_FW > 0x00000302
#define i1480_RCEB_EXTENDED
#endif
struct uwb_rccb;
struct uwb_rceb;
/*
* Common firmware upload handlers
*
* Normally you embed this struct in another one specific to your hw.
*
* @write Write to device's memory from buffer.
* @read Read from device's memory to i1480->evt_buf.
* @setup Setup device after basic firmware is uploaded
* @wait_init_done
* Wait for the device to send a notification saying init
* is done.
* @cmd FOP for issuing the command to the hardware. The
* command data is contained in i1480->cmd_buf and the size
* is supplied as an argument. The command replied is put
* in i1480->evt_buf and the size in i1480->evt_result (or if
* an error, a < 0 errno code).
*
* @cmd_buf Memory buffer used to send commands to the device.
* Allocated by the upper layers i1480_fw_upload().
* Size has to be @buf_size.
* @evt_buf Memory buffer used to place the async notifications
* received by the hw. Allocated by the upper layers
* i1480_fw_upload().
* Size has to be @buf_size.
* @cmd_complete
* Low level driver uses this to notify code waiting afor
* an event that the event has arrived and data is in
* i1480->evt_buf (and size/result in i1480->evt_result).
* @hw_rev
* Use this value to activate dfu code to support new revisions
* of hardware. i1480_init() sets this to a default value.
* It should be updated by the USB and PCI code.
*/
struct i1480 {
struct device *dev;
int (*write)(struct i1480 *, u32 addr, const void *, size_t);
int (*read)(struct i1480 *, u32 addr, size_t);
int (*rc_setup)(struct i1480 *);
void (*rc_release)(struct i1480 *);
int (*wait_init_done)(struct i1480 *);
int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size);
const char *pre_fw_name;
const char *mac_fw_name;
const char *mac_fw_name_deprecate; /* FIXME: Will go away */
const char *phy_fw_name;
u8 hw_rev;
size_t buf_size; /* size of both evt_buf and cmd_buf */
void *evt_buf, *cmd_buf;
ssize_t evt_result;
struct completion evt_complete;
};
static inline
void i1480_init(struct i1480 *i1480)
{
i1480->hw_rev = 1;
init_completion(&i1480->evt_complete);
}
extern int i1480_fw_upload(struct i1480 *);
extern int i1480_pre_fw_upload(struct i1480 *);
extern int i1480_mac_fw_upload(struct i1480 *);
extern int i1480_phy_fw_upload(struct i1480 *);
extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t);
extern int i1480_rceb_check(const struct i1480 *,
const struct uwb_rceb *, const char *, u8,
u8, unsigned);
enum {
/* Vendor specific command type */
i1480_CET_VS1 = 0xfd,
/* i1480 commands */
i1480_CMD_SET_IP_MAS = 0x000e,
i1480_CMD_GET_MAC_PHY_INFO = 0x0003,
i1480_CMD_MPI_WRITE = 0x000f,
i1480_CMD_MPI_READ = 0x0010,
/* i1480 events */
#if i1480_FW > 0x00000302
i1480_EVT_CONFIRM = 0x0002,
i1480_EVT_RM_INIT_DONE = 0x0101,
i1480_EVT_DEV_ADD = 0x0103,
i1480_EVT_DEV_RM = 0x0104,
i1480_EVT_DEV_ID_CHANGE = 0x0105,
i1480_EVT_GET_MAC_PHY_INFO = i1480_CMD_GET_MAC_PHY_INFO,
#else
i1480_EVT_CONFIRM = 0x0002,
i1480_EVT_RM_INIT_DONE = 0x0101,
i1480_EVT_DEV_ADD = 0x0103,
i1480_EVT_DEV_RM = 0x0104,
i1480_EVT_DEV_ID_CHANGE = 0x0105,
i1480_EVT_GET_MAC_PHY_INFO = i1480_EVT_CONFIRM,
#endif
};
struct i1480_evt_confirm {
struct uwb_rceb rceb;
#ifdef i1480_RCEB_EXTENDED
__le16 wParamLength;
#endif
u8 bResultCode;
} __attribute__((packed));
struct i1480_rceb {
struct uwb_rceb rceb;
#ifdef i1480_RCEB_EXTENDED
__le16 wParamLength;
#endif
} __attribute__((packed));
/**
* Get MAC & PHY Information confirm event structure
*
* Confirm event returned by the command.
*/
struct i1480_evt_confirm_GMPI {
#if i1480_FW > 0x00000302
struct uwb_rceb rceb;
__le16 wParamLength;
__le16 status;
u8 mac_addr[6]; /* EUI-64 bit IEEE address [still 8 bytes?] */
u8 dev_addr[2];
__le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */
u8 hw_rev;
u8 phy_vendor;
u8 phy_rev; /* major v = >> 8; minor = v & 0xff */
__le16 mac_caps;
u8 phy_caps[3];
u8 key_stores;
__le16 mcast_addr_stores;
u8 sec_mode_supported;
#else
struct uwb_rceb rceb;
u8 status;
u8 mac_addr[8]; /* EUI-64 bit IEEE address [still 8 bytes?] */
u8 dev_addr[2];
__le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */
__le16 phy_fw_rev; /* major v = >> 8; minor = v & 0xff */
__le16 mac_caps;
u8 phy_caps;
u8 key_stores;
__le16 mcast_addr_stores;
u8 sec_mode_supported;
#endif
} __attribute__((packed));
struct i1480_cmd_mpi_write {
struct uwb_rccb rccb;
__le16 size;
u8 data[];
};
struct i1480_cmd_mpi_read {
struct uwb_rccb rccb;
__le16 size;
struct {
u8 page, offset;
} __attribute__((packed)) data[];
} __attribute__((packed));
struct i1480_evt_mpi_read {
struct uwb_rceb rceb;
#ifdef i1480_RCEB_EXTENDED
__le16 wParamLength;
#endif
u8 bResultCode;
__le16 size;
struct {
u8 page, offset, value;
} __attribute__((packed)) data[];
} __attribute__((packed));
#endif /* #ifndef __i1480_DFU_H__ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel Wireless UWB Link 1480
* Event Size tables for Wired Adaptors
*
* Copyright (C) 2005-2006 Intel Corporation
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
*
* FIXME: docs
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/usb.h>
#include "../uwb.h"
#include "dfu/i1480-dfu.h"
/** Event size table for wEvents 0x00XX */
static struct uwb_est_entry i1480_est_fd00[] = {
/* Anybody expecting this response has to use
* neh->extra_size to specify the real size that will
* come back. */
[i1480_EVT_CONFIRM] = { .size = sizeof(struct i1480_evt_confirm) },
[i1480_CMD_SET_IP_MAS] = { .size = sizeof(struct i1480_evt_confirm) },
#ifdef i1480_RCEB_EXTENDED
[0x09] = {
.size = sizeof(struct i1480_rceb),
.offset = 1 + offsetof(struct i1480_rceb, wParamLength),
},
#endif
};
/** Event size table for wEvents 0x01XX */
static struct uwb_est_entry i1480_est_fd01[] = {
[0xff & i1480_EVT_RM_INIT_DONE] = { .size = sizeof(struct i1480_rceb) },
[0xff & i1480_EVT_DEV_ADD] = { .size = sizeof(struct i1480_rceb) + 9 },
[0xff & i1480_EVT_DEV_RM] = { .size = sizeof(struct i1480_rceb) + 9 },
[0xff & i1480_EVT_DEV_ID_CHANGE] = {
.size = sizeof(struct i1480_rceb) + 2 },
};
static int __init i1480_est_init(void)
{
int result = uwb_est_register(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
i1480_est_fd00,
ARRAY_SIZE(i1480_est_fd00));
if (result < 0) {
printk(KERN_ERR "Can't register EST table fd00: %d\n", result);
return result;
}
result = uwb_est_register(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b,
i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01));
if (result < 0) {
printk(KERN_ERR "Can't register EST table fd01: %d\n", result);
return result;
}
return 0;
}
module_init(i1480_est_init);
static void __exit i1480_est_exit(void)
{
uwb_est_unregister(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
i1480_est_fd00, ARRAY_SIZE(i1480_est_fd00));
uwb_est_unregister(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b,
i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01));
}
module_exit(i1480_est_exit);
MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
MODULE_DESCRIPTION("i1480's Vendor Specific Event Size Tables");
MODULE_LICENSE("GPL");
/**
* USB device ID's that we handle
*
* [so we are loaded when this kind device is connected]
*/
static struct usb_device_id __used i1480_est_id_table[] = {
{ USB_DEVICE(0x8086, 0xdf3b), },
{ USB_DEVICE(0x8086, 0x0c3b), },
{ },
};
MODULE_DEVICE_TABLE(usb, i1480_est_id_table);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* UWB Multi-interface Controller driver management.
*
* Copyright (C) 2007 Cambridge Silicon Radio Ltd.
*/
#include <linux/kernel.h>
#include <linux/export.h>
#include "include/umc.h"
int __umc_driver_register(struct umc_driver *umc_drv, struct module *module,
const char *mod_name)
{
umc_drv->driver.name = umc_drv->name;
umc_drv->driver.owner = module;
umc_drv->driver.mod_name = mod_name;
umc_drv->driver.bus = &umc_bus_type;
return driver_register(&umc_drv->driver);
}
EXPORT_SYMBOL_GPL(__umc_driver_register);
/**
* umc_driver_register - unregister a UMC capabiltity driver.
* @umc_drv: pointer to the driver.
*/
void umc_driver_unregister(struct umc_driver *umc_drv)
{
driver_unregister(&umc_drv->driver);
}
EXPORT_SYMBOL_GPL(umc_driver_unregister);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
TODO: Remove in late 2019 unless there are users
There seems to not be any real wireless USB devices anywhere in the wild
anymore. It turned out to be a failed technology :(
This will be removed from the tree if no one objects.
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment